├── header ├── tools ├── Sprite64.png ├── Sprite64.rar ├── mkdfs │ ├── Makefile │ └── mkdfs.c ├── dumpdfs │ └── Makefile ├── mksprite │ ├── Makefile │ ├── convtool.c │ └── mksprite.c ├── Makefile ├── build ├── chksum64.c └── n64tool.c ├── examples ├── fire │ ├── fire.gif │ ├── test.z64 │ ├── filesystem │ │ ├── 1.sprite │ │ ├── 10.sprite │ │ ├── 11.sprite │ │ ├── 12.sprite │ │ ├── 13.sprite │ │ ├── 14.sprite │ │ ├── 15.sprite │ │ ├── 16.sprite │ │ ├── 17.sprite │ │ ├── 18.sprite │ │ ├── 19.sprite │ │ ├── 2.sprite │ │ ├── 20.sprite │ │ ├── 21.sprite │ │ ├── 22.sprite │ │ ├── 23.sprite │ │ ├── 24.sprite │ │ ├── 25.sprite │ │ ├── 26.sprite │ │ ├── 27.sprite │ │ ├── 28.sprite │ │ ├── 29.sprite │ │ ├── 3.sprite │ │ ├── 30.sprite │ │ ├── 31.sprite │ │ ├── 32.sprite │ │ ├── 33.sprite │ │ ├── 34.sprite │ │ ├── 35.sprite │ │ ├── 36.sprite │ │ ├── 37.sprite │ │ ├── 38.sprite │ │ ├── 39.sprite │ │ ├── 4.sprite │ │ ├── 40.sprite │ │ ├── 41.sprite │ │ ├── 42.sprite │ │ ├── 43.sprite │ │ ├── 44.sprite │ │ ├── 45.sprite │ │ ├── 46.sprite │ │ ├── 47.sprite │ │ ├── 5.sprite │ │ ├── 6.sprite │ │ ├── 7.sprite │ │ ├── 8.sprite │ │ └── 9.sprite │ ├── Makefile │ ├── system.c │ ├── controls.c │ └── test.c └── tlut │ ├── test.z64 │ ├── snapshot.png │ ├── filesystem │ ├── 0.sprite │ ├── 1.sprite │ ├── 10.sprite │ ├── 11.sprite │ ├── 12.sprite │ ├── 13.sprite │ ├── 14.sprite │ ├── 15.sprite │ ├── 16.sprite │ ├── 17.sprite │ ├── 18.sprite │ ├── 2.sprite │ ├── 3.sprite │ ├── 4.sprite │ ├── 5.sprite │ ├── 6.sprite │ ├── 7.sprite │ ├── 8.sprite │ └── 9.sprite │ ├── Makefile │ ├── system.c │ ├── controls.c │ └── test.c ├── .gitignore ├── include ├── dma.h ├── dir.h ├── audio.h ├── console.h ├── exception.h ├── interrupt.h ├── display.h ├── rsp.h ├── mempak.h ├── dfsinternal.h ├── dragonfs.h ├── libdragon.h ├── graphics.h ├── timer.h ├── rdp.h ├── n64sys.h ├── controller.h ├── regsinternal.h └── system.h ├── README.md ├── src ├── do_ctors.c ├── entrypoint.S ├── entrypoint_2.S ├── exception.c ├── dma.c ├── n64sys.c ├── inthandler.S ├── regs.S ├── console.c └── timer.c ├── LICENSE.md ├── n64ld_cpp.x ├── n64ld_exp_cpp.x ├── n64ld.x ├── Makefile └── files.in /header: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/header -------------------------------------------------------------------------------- /tools/Sprite64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/tools/Sprite64.png -------------------------------------------------------------------------------- /tools/Sprite64.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/tools/Sprite64.rar -------------------------------------------------------------------------------- /examples/fire/fire.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/fire.gif -------------------------------------------------------------------------------- /examples/fire/test.z64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/test.z64 -------------------------------------------------------------------------------- /examples/tlut/test.z64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/test.z64 -------------------------------------------------------------------------------- /examples/tlut/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/snapshot.png -------------------------------------------------------------------------------- /examples/fire/filesystem/1.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/1.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/10.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/10.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/11.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/11.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/12.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/12.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/13.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/13.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/14.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/14.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/15.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/15.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/16.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/16.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/17.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/17.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/18.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/18.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/19.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/19.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/2.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/2.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/20.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/20.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/21.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/21.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/22.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/22.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/23.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/23.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/24.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/24.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/25.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/25.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/26.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/26.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/27.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/27.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/28.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/28.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/29.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/29.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/3.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/3.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/30.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/30.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/31.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/31.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/32.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/32.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/33.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/33.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/34.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/34.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/35.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/35.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/36.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/36.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/37.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/37.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/38.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/38.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/39.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/39.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/4.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/4.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/40.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/40.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/41.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/41.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/42.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/42.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/43.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/43.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/44.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/44.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/45.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/45.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/46.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/46.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/47.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/47.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/5.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/5.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/6.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/6.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/7.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/7.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/8.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/8.sprite -------------------------------------------------------------------------------- /examples/fire/filesystem/9.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/fire/filesystem/9.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/0.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/0.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/1.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/1.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/10.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/10.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/11.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/11.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/12.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/12.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/13.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/13.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/14.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/14.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/15.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/15.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/16.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/16.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/17.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/17.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/18.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/18.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/2.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/2.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/3.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/3.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/4.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/4.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/5.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/5.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/6.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/6.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/7.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/7.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/8.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/8.sprite -------------------------------------------------------------------------------- /examples/tlut/filesystem/9.sprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conker64/libdragon/HEAD/examples/tlut/filesystem/9.sprite -------------------------------------------------------------------------------- /tools/mkdfs/Makefile: -------------------------------------------------------------------------------- 1 | INSTALLDIR = $(N64_INST) 2 | CFLAGS = -std=gnu99 -O2 -Wall -Werror -I../../include 3 | 4 | all: mkdfs 5 | 6 | mkdfs: mkdfs.c 7 | 8 | install: mkdfs 9 | install -m 0755 mkdfs $(INSTALLDIR)/bin 10 | 11 | .PHONY: clean install 12 | 13 | clean: 14 | rm -rf mkdfs 15 | -------------------------------------------------------------------------------- /tools/dumpdfs/Makefile: -------------------------------------------------------------------------------- 1 | INSTALLDIR = $(N64_INST) 2 | CFLAGS = -std=gnu99 -O2 -Wall -I../../include 3 | 4 | all: dumpdfs 5 | 6 | dumpdfs: dumpdfs.c 7 | 8 | install: dumpdfs 9 | install -m 0755 dumpdfs $(INSTALLDIR)/bin 10 | 11 | .PHONY: clean install 12 | 13 | clean: 14 | rm -rf dumpdfs 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Build files 2 | *.elf 3 | *.o 4 | *.a 5 | *.bin 6 | *.dfs 7 | build/ 8 | build_gcc/ 9 | tools/chksum64 10 | tools/dumpdfs/dumpdfs 11 | tools/mkdfs/mkdfs 12 | tools/mksprite/convtool 13 | tools/mksprite/mksprite 14 | tools/n64tool 15 | 16 | ## Cygwin/MinGW junk 17 | *.exe 18 | 19 | ## OSX junk 20 | .DS_Store 21 | .Trashes 22 | ._* 23 | 24 | ## Temporary files 25 | *.tmp 26 | *.swp 27 | *~ 28 | -------------------------------------------------------------------------------- /tools/mksprite/Makefile: -------------------------------------------------------------------------------- 1 | INSTALLDIR = $(N64_INST) 2 | CFLAGS = -std=gnu99 -O2 -Wall -I../../include 3 | LDFLAGS = -lpng 4 | 5 | all: mksprite convtool 6 | 7 | mksprite: mksprite.o 8 | $(CC) $< -o $@ $(LDFLAGS) 9 | 10 | %o: %.c 11 | $(CC) $(CFLAGS) -c -o $@ $< 12 | 13 | convtool: convtool.c 14 | 15 | install: mksprite convtool 16 | install -m 0755 mksprite $(INSTALLDIR)/bin 17 | install -m 0755 convtool $(INSTALLDIR)/bin 18 | 19 | .PHONY: clean install 20 | 21 | clean: 22 | rm -rf mksprite 23 | rm -rf convtool 24 | -------------------------------------------------------------------------------- /include/dma.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dma.h 3 | * @brief DMA Controller 4 | * @ingroup dma 5 | */ 6 | #ifndef __LIBDRAGON_DMA_H 7 | #define __LIBDRAGON_DMA_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void dma_write(void * ram_address, unsigned long pi_address, unsigned long len); 14 | void dma_read(void * ram_address, unsigned long pi_address, unsigned long len); 15 | volatile int dma_busy(); 16 | 17 | /* 32 bit IO read from PI device */ 18 | uint32_t io_read(uint32_t pi_address); 19 | 20 | /* 32 bit IO write to PI device */ 21 | void io_write(uint32_t pi_address, uint32_t data); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libdragon 2 | Libdragon with extended RDP features: 3 | - Sprite flip (Vertically, horizontally or both) 4 | - Sprite zooming (Scale X, Scale Y or both) 5 | - Sprite center align 6 | - Alpha blending (32 levels on 16bit mode) 7 | - Additive blending (somewhat) 8 | - Intensify / Color Mask and other kind of effects using different color combiners 9 | - 4 and 8bit texture support (Color Index) 10 | - Set other modes options: enable copy / 1cycle, enable tlut, enable bilinear filter, enable atomic prim, etc 11 | - Framebuffer effects 12 | - Bug fixes on 32bit mode / textures 13 | - Some other fixes 14 | 15 | Original source: 16 | https://github.com/DragonMinded/libdragon 17 | 18 | Somes changes applied from Chillywilly's libdragon (2014-11-12) 19 | -------------------------------------------------------------------------------- /src/do_ctors.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file do_ctors.c 3 | * @brief C++ constructor handling 4 | * @ingroup system 5 | */ 6 | #include 7 | 8 | /** 9 | * @addtogroup system 10 | * @{ 11 | */ 12 | 13 | /** @brief Function pointer */ 14 | typedef void (*func_ptr)(void); 15 | 16 | /** @brief Pointer to the size of the constructor list */ 17 | extern uint32_t __CTOR_LIST_SIZE__; 18 | /** @brief Pointer to the beginning of the constructor list */ 19 | extern func_ptr __CTOR_LIST__[]; 20 | /** @brief Pointer to the end of the constructor list */ 21 | extern func_ptr __CTOR_END__[]; 22 | 23 | /** 24 | * @brief Execute global constructors 25 | */ 26 | void __do_global_ctors() 27 | { 28 | unsigned int tot_constructors = __CTOR_LIST_SIZE__; 29 | for (void (**f)(void) = (void (**)(void))(__CTOR_LIST__); tot_constructors > 0; tot_constructors--, f++) 30 | (**f)(); 31 | } 32 | 33 | /** @} */ 34 | -------------------------------------------------------------------------------- /include/dir.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dir.h 3 | * @brief Directory handling 4 | * @ingroup system 5 | */ 6 | #ifndef __LIBDRAGON_DIR_H 7 | #define __LIBDRAGON_DIR_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | * @addtogroup system 15 | * @{ 16 | */ 17 | 18 | /** 19 | * @name Directory entry type definitions 20 | * @{ 21 | */ 22 | /** @brief Regular file */ 23 | #define DT_REG 1 24 | /** @brief Directory */ 25 | #define DT_DIR 2 26 | /** @} */ 27 | 28 | /** 29 | * @brief Directory entry structure 30 | */ 31 | typedef struct 32 | { 33 | /** @brief The name of the directory entry */ 34 | char d_name[256]; 35 | /** @brief The type of the directory entry. See #DT_REG and #DT_DIR. */ 36 | int d_type; 37 | } dir_t; 38 | 39 | /** @} */ 40 | 41 | int dir_findfirst( const char * const path, dir_t *dir ); 42 | int dir_findnext( const char * const path, dir_t *dir ); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | INSTALLDIR = $(N64_INST) 2 | 3 | all: build 4 | build: dumpdfs mkdfs mksprite chksum64 n64tool 5 | clean: chksum64-clean n64tool-clean dumpdfs-clean mkdfs-clean mksprite-clean 6 | 7 | chksum64: chksum64.c 8 | gcc -o chksum64 chksum64.c 9 | chksum64-clean: 10 | rm -rf chksum64 11 | 12 | n64tool: n64tool.c 13 | gcc -o n64tool n64tool.c 14 | n64tool-clean: 15 | rm -rf n64tool 16 | 17 | dumpdfs: 18 | make -C dumpdfs 19 | dumpdfs-install: 20 | make -C dumpdfs install 21 | dumpdfs-clean: 22 | make -C dumpdfs clean 23 | 24 | mkdfs: 25 | make -C mkdfs 26 | mkdfs-install: 27 | make -C mkdfs install 28 | mkdfs-clean: 29 | make -C mkdfs clean 30 | 31 | mksprite: 32 | make -C mksprite 33 | mksprite-install: 34 | make -C mksprite install 35 | mksprite-clean: 36 | make -C mksprite clean 37 | 38 | install: dumpdfs-install mkdfs-install mksprite-install 39 | install -m 0755 chksum64 $(INSTALLDIR)/bin 40 | install -m 0755 n64tool $(INSTALLDIR)/bin 41 | 42 | .PHONY: dumpdfs mkdfs mksprite dumpdfs-install mkdfs-install mksprite-install chksum64-clean n64tool-clean 43 | .PHONY: dumpdfs-clean mkdfs-clean mksprite-clean 44 | -------------------------------------------------------------------------------- /include/audio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file audio.h 3 | * @brief Audio Subsystem 4 | * @ingroup audio 5 | */ 6 | #ifndef __LIBDRAGON_AUDIO_H 7 | #define __LIBDRAGON_AUDIO_H 8 | 9 | #include 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | /** 17 | * @brief Will be called periodically when more sample data is needed. 18 | * 19 | * @param[in] buffer 20 | * The address to write the sample data to 21 | * @param[in] numsamples 22 | * The number of samples to write to the buffer 23 | * Note: this is the number of samples per channel, so clients 24 | * should write twice this number of samples (interleaved). 25 | */ 26 | typedef void(*audio_fill_buffer_callback)(short *buffer, size_t numsamples); 27 | 28 | void audio_init(const int frequency, int numbuffers); 29 | void audio_set_buffer_callback(audio_fill_buffer_callback fill_buffer_callback); 30 | void audio_pause(bool pause); 31 | void audio_write(const short * const buffer); 32 | volatile int audio_can_write(); 33 | void audio_write_silence(); 34 | void audio_close(); 35 | int audio_get_frequency(); 36 | int audio_get_buffer_length(); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /examples/fire/Makefile: -------------------------------------------------------------------------------- 1 | ROOTDIR = $(N64_INST) 2 | GCCN64PREFIX = $(ROOTDIR)/bin/mips64-elf- 3 | CHKSUM64PATH = $(ROOTDIR)/bin/chksum64 4 | MKDFSPATH = $(ROOTDIR)/bin/mkdfs 5 | HEADERPATH = $(ROOTDIR)/mips64-elf/lib 6 | N64TOOL = $(ROOTDIR)/bin/n64tool 7 | HEADERNAME = header 8 | LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -lm -ldragon -lc -ldragonsys -Tn64ld.x 9 | PROG_NAME = test 10 | CFLAGS = -std=gnu99 -march=vr4300 -mtune=vr4300 -O2 -Wall -Werror -I$(ROOTDIR)/mips64-elf/include 11 | ASFLAGS = -mtune=vr4300 -march=vr4300 12 | CC = $(GCCN64PREFIX)gcc 13 | AS = $(GCCN64PREFIX)as 14 | LD = $(GCCN64PREFIX)ld 15 | OBJCOPY = $(GCCN64PREFIX)objcopy 16 | 17 | $(PROG_NAME).z64: $(PROG_NAME).elf test.dfs 18 | $(OBJCOPY) $(PROG_NAME).elf $(PROG_NAME).bin -O binary 19 | rm -f $(PROG_NAME).z64 20 | $(N64TOOL) -l 2M -t "test" -h $(HEADERPATH)/$(HEADERNAME) -o $(PROG_NAME).z64 $(PROG_NAME).bin -s 1M test.dfs 21 | $(CHKSUM64PATH) $(PROG_NAME).z64 22 | 23 | $(PROG_NAME).elf : $(PROG_NAME).o 24 | $(LD) -o $(PROG_NAME).elf $(PROG_NAME).o $(LINK_FLAGS) 25 | 26 | copy: $(PROG_NAME).z64 27 | cp $(PROG_NAME).z64 ~/public_html/ 28 | 29 | test.dfs: 30 | $(MKDFSPATH) test.dfs ./filesystem/ 31 | 32 | all: $(PROG_NAME).z64 33 | 34 | clean: 35 | rm -f *.z64 *.elf *.o *.bin *.dfs 36 | -------------------------------------------------------------------------------- /examples/tlut/Makefile: -------------------------------------------------------------------------------- 1 | ROOTDIR = $(N64_INST) 2 | GCCN64PREFIX = $(ROOTDIR)/bin/mips64-elf- 3 | CHKSUM64PATH = $(ROOTDIR)/bin/chksum64 4 | MKDFSPATH = $(ROOTDIR)/bin/mkdfs 5 | HEADERPATH = $(ROOTDIR)/mips64-elf/lib 6 | N64TOOL = $(ROOTDIR)/bin/n64tool 7 | HEADERNAME = header 8 | LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -lm -ldragon -lc -ldragonsys -Tn64ld.x 9 | PROG_NAME = test 10 | CFLAGS = -std=gnu99 -march=vr4300 -mtune=vr4300 -O2 -Wall -Werror -I$(ROOTDIR)/mips64-elf/include 11 | ASFLAGS = -mtune=vr4300 -march=vr4300 12 | CC = $(GCCN64PREFIX)gcc 13 | AS = $(GCCN64PREFIX)as 14 | LD = $(GCCN64PREFIX)ld 15 | OBJCOPY = $(GCCN64PREFIX)objcopy 16 | 17 | $(PROG_NAME).z64: $(PROG_NAME).elf test.dfs 18 | $(OBJCOPY) $(PROG_NAME).elf $(PROG_NAME).bin -O binary 19 | rm -f $(PROG_NAME).z64 20 | $(N64TOOL) -l 2M -t "test" -h $(HEADERPATH)/$(HEADERNAME) -o $(PROG_NAME).z64 $(PROG_NAME).bin -s 1M test.dfs 21 | $(CHKSUM64PATH) $(PROG_NAME).z64 22 | 23 | $(PROG_NAME).elf : $(PROG_NAME).o 24 | $(LD) -o $(PROG_NAME).elf $(PROG_NAME).o $(LINK_FLAGS) 25 | 26 | copy: $(PROG_NAME).z64 27 | cp $(PROG_NAME).z64 ~/public_html/ 28 | 29 | test.dfs: 30 | $(MKDFSPATH) test.dfs ./filesystem/ 31 | 32 | all: $(PROG_NAME).z64 33 | 34 | clean: 35 | rm -f *.z64 *.elf *.o *.bin *.dfs 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /examples/tlut/system.c: -------------------------------------------------------------------------------- 1 | // RAND FUNCTION 2 | #define MIN(a,b) (((a)<(b))?(a):(b)) 3 | #define MAX(a,b) (((a)>(b))?(a):(b)) 4 | 5 | // enable palette (tlut) 6 | #define EN_TLUT 0x00800000000000 7 | // enable atomic prim, 1st primitive bandwitdh save 8 | #define ATOMIC_PRIM 0x80000000000000 9 | // enable perspective correction 10 | #define PERSP_TEX_EN 0x08000000000000 11 | // select alpha dither 12 | #define ALPHA_DITHER_SEL_PATTERN 0x00000000000000 13 | #define ALPHA_DITHER_SEL_PATTERNB 0x00001000000000 14 | #define ALPHA_DITHER_SEL_NOISE 0x00002000000000 15 | #define ALPHA_DITHER_SEL_NO_DITHER 0x00003000000000 16 | // select rgb dither 17 | #define RGB_DITHER_SEL_MAGIC_SQUARE_MATRIX 0x00000000000000 18 | #define RGB_DITHER_SEL_STANDARD_BAYER_MATRIX 0x00004000000000 19 | #define RGB_DITHER_SEL_NOISE 0x00008000000000 20 | #define RGB_DITHER_SEL_NO_DITHER 0x0000C000000000 21 | // enable texture filtering 22 | #define SAMPLE_TYPE 0x00200000000000 23 | 24 | uint16_t framerate_refresh=0; 25 | 26 | // FPS 27 | void update_counter() 28 | { 29 | framerate_refresh=1; 30 | } 31 | 32 | // RANDX 33 | int randx(int min_n, int max_n) 34 | { 35 | int num1 = MIN( min_n, max_n ) ; 36 | int num2 = MAX( min_n, max_n ) ; 37 | int var = num2 - num1 + 1; 38 | 39 | if ( var > RAND_MAX ) 40 | return num1 + rand() * ((( double ) var ) / RAND_MAX ); 41 | else 42 | return num1 + rand() % var; 43 | } -------------------------------------------------------------------------------- /include/console.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file console.h 3 | * @brief Console Support 4 | * @ingroup console 5 | */ 6 | 7 | #ifndef __LIBDRAGON_CONSOLE_H 8 | #define __LIBDRAGON_CONSOLE_H 9 | 10 | #include "display.h" 11 | 12 | /** 13 | * @addtogroup console 14 | * @{ 15 | */ 16 | 17 | /** 18 | * @name Console Render Modes 19 | * @brief Modes for rendering the console to the screen 20 | * 21 | * @{ 22 | */ 23 | 24 | /** 25 | * @brief Manual Rendering 26 | * 27 | * The user must call #console_render when the screen should be updated 28 | */ 29 | #define RENDER_MANUAL 0 30 | /** 31 | * @brief Automatic Rendering 32 | * 33 | * The screen will be updated on every console interaction 34 | */ 35 | #define RENDER_AUTOMATIC 1 36 | /** @} */ 37 | 38 | /** 39 | * @name Console Dimensions 40 | * @{ 41 | */ 42 | 43 | /** @brief The console width in characters */ 44 | #define CONSOLE_WIDTH 35 45 | /** @brief The console height in characters */ 46 | #define CONSOLE_HEIGHT 25 47 | /** @} */ 48 | 49 | /** 50 | * @brief Tab width 51 | * 52 | * @note This needs to divide evenly into #CONSOLE_WIDTH 53 | */ 54 | #define TAB_WIDTH 5 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | void console_init(); 61 | void console_close(); 62 | void console_set_render_mode(int mode); 63 | void console_clear(); 64 | void console_render(); 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | 70 | /** @} */ /* console */ 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /examples/fire/system.c: -------------------------------------------------------------------------------- 1 | // RAND FUNCTION 2 | #define MIN(a,b) (((a)<(b))?(a):(b)) 3 | #define MAX(a,b) (((a)>(b))?(a):(b)) 4 | 5 | // enable palette (tlut) 6 | #define EN_TLUT 0x00800000000000 7 | // enable atomic prim, 1st primitive bandwitdh save 8 | #define ATOMIC_PRIM 0x80000000000000 9 | // enable perspective correction 10 | #define PERSP_TEX_EN 0x08000000000000 11 | // select alpha dither 12 | #define ALPHA_DITHER_SEL_PATTERN 0x00000000000000 13 | #define ALPHA_DITHER_SEL_PATTERNB 0x00001000000000 14 | #define ALPHA_DITHER_SEL_NOISE 0x00002000000000 15 | #define ALPHA_DITHER_SEL_NO_DITHER 0x00003000000000 16 | // select rgb dither 17 | #define RGB_DITHER_SEL_MAGIC_SQUARE_MATRIX 0x00000000000000 18 | #define RGB_DITHER_SEL_STANDARD_BAYER_MATRIX 0x00004000000000 19 | #define RGB_DITHER_SEL_NOISE 0x00008000000000 20 | #define RGB_DITHER_SEL_NO_DITHER 0x0000C000000000 21 | // enable texture filtering 22 | #define SAMPLE_TYPE 0x00200000000000 23 | 24 | uint16_t framerate_refresh=0; 25 | 26 | // FPS 27 | void update_counter() 28 | { 29 | framerate_refresh=1; 30 | } 31 | 32 | // RANDX 33 | int randx(int min_n, int max_n) 34 | { 35 | int num1 = MIN( min_n, max_n ) ; 36 | int num2 = MAX( min_n, max_n ) ; 37 | int var = num2 - num1 + 1; 38 | 39 | if ( var > RAND_MAX ) 40 | return num1 + rand() * ((( double ) var ) / RAND_MAX ); 41 | else 42 | return num1 + rand() % var; 43 | } 44 | 45 | // GET_DISTX 46 | int get_distx(int ang, int dist) 47 | { 48 | double angle = ang * M_PI / 180000.0 ; 49 | return ( int )( dist * cos( angle ) ) ; 50 | } -------------------------------------------------------------------------------- /tools/mksprite/convtool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /** 5 | * To use this file, pipe a sprite of the old format into stdin, and 6 | * redirect stdout to a second file of your chosing. The sprite header 7 | * will be converted. This tool has no error checking and assumes a valid 8 | * sprite header. It is provided merely for convenience. 9 | */ 10 | 11 | int main( int argc, char *argv[] ) 12 | { 13 | uint8_t zero = 0; 14 | uint8_t val; 15 | int ret; 16 | 17 | /* Read in old width */ 18 | ret = fread( &val, sizeof( val ), 1, stdin ); 19 | 20 | /* Write empty value and then new */ 21 | fwrite( &zero, sizeof( zero ), 1, stdout ); 22 | fwrite( &val, sizeof( val ), 1, stdout ); 23 | 24 | /* Read in old height */ 25 | ret = fread( &val, sizeof( val ), 1, stdin ); 26 | 27 | /* Write empty value and then new */ 28 | fwrite( &zero, sizeof( zero ), 1, stdout ); 29 | fwrite( &val, sizeof( val ), 1, stdout ); 30 | 31 | /* Straight copy of bitdepth and format */ 32 | ret = fread( &val, sizeof( val ), 1, stdin ); 33 | fwrite( &val, sizeof( val ), 1, stdout ); 34 | 35 | ret = fread( &val, sizeof( val ), 1, stdin ); 36 | fwrite( &val, sizeof( val ), 1, stdout ); 37 | 38 | /* Assuming horizontal and vertical stride of 1 */ 39 | val = 1; 40 | fwrite( &val, sizeof( val ), 1, stdout ); 41 | fwrite( &val, sizeof( val ), 1, stdout ); 42 | 43 | /* Now just byte copy until end of stream */ 44 | while( !feof( stdin ) ) 45 | { 46 | ret = fread( &val, sizeof( val ), 1, stdin ); 47 | 48 | if( !feof( stdin ) ) 49 | { 50 | /* Only copy out if the last read didn't make an eof */ 51 | fwrite( &val, sizeof( val ), 1, stdout ); 52 | } 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /include/exception.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file exception.h 3 | * @brief Exception Handler 4 | * @ingroup exceptions 5 | */ 6 | #ifndef __LIBDRAGON_EXCEPTION_H 7 | #define __LIBDRAGON_EXCEPTION_H 8 | 9 | #include 10 | 11 | /** 12 | * @addtogroup exceptions 13 | * @{ 14 | */ 15 | 16 | /** 17 | * @brief Exception types 18 | */ 19 | enum 20 | { 21 | /** @brief Unknown exception */ 22 | EXCEPTION_TYPE_UNKNOWN = 0, 23 | /** @brief Reset exception */ 24 | EXCEPTION_TYPE_RESET, 25 | /** @brief Critical exception */ 26 | EXCEPTION_TYPE_CRITICAL 27 | }; 28 | 29 | /** 30 | * @brief Structure representing a register block 31 | * 32 | * DO NOT modify the order unless editing inthandler.S 33 | */ 34 | typedef volatile struct 35 | { 36 | /** @brief General purpose registers 1-32 */ 37 | volatile uint64_t gpr[32]; 38 | /** @brief SR */ 39 | volatile uint32_t sr; 40 | /** @brief EPC */ 41 | volatile uint32_t epc; 42 | /** @brief HI */ 43 | volatile uint64_t hi; 44 | /** @brief LO */ 45 | volatile uint64_t lo; 46 | /** @brief FC31 */ 47 | volatile uint64_t fc31; 48 | /** @brief Floating point registers 1-32 */ 49 | volatile uint64_t fpr[32]; 50 | } reg_block_t; 51 | 52 | /** 53 | * @brief Structure representing an exception 54 | */ 55 | typedef struct 56 | { 57 | /** 58 | * @brief Exception type 59 | * @see #EXCEPTION_TYPE_RESET, #EXCEPTION_TYPE_CRITICAL 60 | */ 61 | int32_t type; 62 | /** @brief String information of exception */ 63 | const char* info; 64 | /** @brief Registers at point of exception */ 65 | volatile const reg_block_t* regs; 66 | } exception_t; 67 | 68 | /** @} */ 69 | 70 | #ifdef __cplusplus 71 | extern "C" { 72 | #endif 73 | 74 | void register_exception_handler( void (*cb)(exception_t *) ); 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /include/interrupt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file interrupt.h 3 | * @brief Interrupt Controller 4 | * @ingroup interrupt 5 | */ 6 | #ifndef __LIBDRAGON_INTERRUPT_H 7 | #define __LIBDRAGON_INTERRUPT_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | * @addtogroup interrupt 15 | * @{ 16 | */ 17 | 18 | /** 19 | * @brief State of interrupts on the system 20 | */ 21 | typedef enum 22 | { 23 | /** @brief Interrupt controller has not been initialized */ 24 | INTERRUPTS_UNINITIALIZED, 25 | /** @brief Interrupts are currently disabled */ 26 | INTERRUPTS_DISABLED, 27 | /** @brief Interrupts are currently enabled */ 28 | INTERRUPTS_ENABLED 29 | } interrupt_state_t; 30 | 31 | /** @} */ 32 | 33 | void register_AI_handler( void (*callback)() ); 34 | void register_VI_handler( void (*callback)() ); 35 | void register_PI_handler( void (*callback)() ); 36 | void register_DP_handler( void (*callback)() ); 37 | void register_TI_handler( void (*callback)() ); 38 | void register_SI_handler( void (*callback)() ); 39 | void register_SP_handler( void (*callback)() ); 40 | 41 | void unregister_AI_handler( void (*callback)() ); 42 | void unregister_VI_handler( void (*callback)() ); 43 | void unregister_PI_handler( void (*callback)() ); 44 | void unregister_DP_handler( void (*callback)() ); 45 | void unregister_TI_handler( void (*callback)() ); 46 | void unregister_SI_handler( void (*callback)() ); 47 | void unregister_SP_handler( void (*callback)() ); 48 | 49 | void set_AI_interrupt( int active ); 50 | void set_VI_interrupt( int active, unsigned long line ); 51 | void set_PI_interrupt( int active ); 52 | void set_DP_interrupt( int active ); 53 | void set_SI_interrupt( int active ); 54 | void set_SP_interrupt( int active ); 55 | 56 | void init_interrupts(); 57 | 58 | void enable_interrupts(); 59 | void disable_interrupts(); 60 | 61 | interrupt_state_t get_interrupts_state(); 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/entrypoint.S: -------------------------------------------------------------------------------- 1 | /* 2 | * N64 init code for GNU as 3 | */ 4 | 5 | #include "regs.S" 6 | 7 | .section .boot 8 | .global _start 9 | _start: 10 | lw t0, 0x80000318 /* memory size */ 11 | li t1, 0x7FFFFFF0 12 | addu sp,t0,t1 /* init stack */ 13 | la gp, _gp /* init data pointer */ 14 | li v0, 8 15 | sw v0,(0xbfc007fc) /* magic N64 hardware init */ 16 | 17 | /* a bit from libgloss so we start at a known state */ 18 | li v0,SR_CU1|SR_PE|SR_FR|SR_KX|SR_SX|SR_UX 19 | mtc0 v0,C0_SR 20 | mtc0 $0,C0_CAUSE 21 | 22 | /* copy code and data */ 23 | la a0, __text_start 24 | la a1, __data_end 25 | subu a2,a0,0x80000400 /* skip over .boot section */ 26 | addu a2,a2,0xB0001000 /* address in rom */ 27 | data_init: 28 | lw t0,(a2) 29 | addiu a2,4 30 | sw t0,(a0) 31 | addiu a0,4 32 | bltu a0,a1, data_init 33 | nop 34 | 35 | /* make sure code and data are actually written */ 36 | la a0,__text_start 37 | la a1,__data_end 38 | sub a1,a0 39 | jal data_cache_hit_writeback_invalidate 40 | nop 41 | 42 | /* fill .bss with 0s */ 43 | la a0, __bss_start 44 | la a1, __bss_end 45 | bss_init: 46 | sd $0,(a0) 47 | addiu a0,8 48 | bltu a0,a1, bss_init 49 | nop 50 | 51 | /* make sure .bss is actually written */ 52 | la a0,__bss_start 53 | la a1,__bss_end 54 | sub a1,a0 55 | jal data_cache_hit_writeback_invalidate 56 | nop 57 | 58 | /* load interrupt vector */ 59 | la t0,intvector 60 | la t1,0xa0000000 61 | la t2,4 62 | loadintvectorloop: 63 | lw t3,(t0) 64 | sw t3,0(t1) 65 | sw t3,0x80(t1) 66 | sw t3,0x100(t1) 67 | sw t3,0x180(t1) 68 | /* sync */ 69 | cache HIT_INVALIDATE_I,0(t1) 70 | cache HIT_INVALIDATE_I,0x80(t1) 71 | cache HIT_INVALIDATE_I,0x100(t1) 72 | cache HIT_INVALIDATE_I,0x180(t1) 73 | addi t0,4 74 | addi t1,4 75 | addiu t2,-1 76 | bnez t2,loadintvectorloop 77 | nop 78 | 79 | jal main /* call main app */ 80 | nop 81 | 82 | deadloop: 83 | j deadloop 84 | nop 85 | 86 | intvector: 87 | la k1,inthandler 88 | jr k1 89 | nop 90 | 91 | .section .code 92 | -------------------------------------------------------------------------------- /include/display.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file display.h 3 | * @brief Display Subsystem 4 | * @ingroup display 5 | */ 6 | #ifndef __LIBDRAGON_DISPLAY_H 7 | #define __LIBDRAGON_DISPLAY_H 8 | 9 | #include 10 | 11 | /** 12 | * @addtogroup display 13 | * @{ 14 | */ 15 | 16 | /** 17 | * @brief Valid video resolutions 18 | */ 19 | typedef enum 20 | { 21 | /** @brief 320x240 mode */ 22 | RESOLUTION_320x240, 23 | /** @brief 640x480 mode */ 24 | RESOLUTION_640x480, 25 | /** @brief 256x240 mode */ 26 | RESOLUTION_256x240, 27 | /** @brief 512x480 mode */ 28 | RESOLUTION_512x480 29 | } resolution_t; 30 | 31 | /** @brief Valid bit depths */ 32 | typedef enum 33 | { 34 | /** @brief 16 bits per pixel (5-5-5-1) */ 35 | DEPTH_16_BPP, 36 | /** @brief 32 bits per pixel (8-8-8-8) */ 37 | DEPTH_32_BPP 38 | } bitdepth_t; 39 | 40 | /** @brief Valid gamma correction settings */ 41 | typedef enum 42 | { 43 | /** @brief Uncorrected gamma */ 44 | GAMMA_NONE, 45 | /** @brief Corrected gamma */ 46 | GAMMA_CORRECT, 47 | /** @brief Corrected gamma with hardware dither */ 48 | GAMMA_CORRECT_DITHER 49 | } gamma_t; 50 | 51 | /** @brief Valid antialiasing settings */ 52 | typedef enum 53 | { 54 | /** @brief No anti-aliasing */ 55 | ANTIALIAS_OFF, 56 | /** @brief Resampling anti-aliasing */ 57 | ANTIALIAS_RESAMPLE, 58 | /** @brief Anti-aliasing and resampling with fetch-on-need */ 59 | ANTIALIAS_RESAMPLE_FETCH_NEEDED, 60 | /** @brief Anti-aliasing and resampling with fetch-always */ 61 | ANTIALIAS_RESAMPLE_FETCH_ALWAYS 62 | } antialias_t; 63 | 64 | /** @brief Display context */ 65 | typedef int display_context_t; 66 | 67 | #ifdef __cplusplus 68 | extern "C" { 69 | #endif 70 | 71 | void display_init( resolution_t res, bitdepth_t bit, uint32_t num_buffers, gamma_t gamma, antialias_t aa ); 72 | display_context_t display_lock(); 73 | void display_show(display_context_t disp); 74 | void display_close(); 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | /** @} */ /* display */ 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/rsp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rsp.h 3 | * @brief Hardware Coprocessor Interface 4 | * @ingroup rsp 5 | */ 6 | #ifndef __LIBDRAGON_RSP_H 7 | #define __LIBDRAGON_RSP_H 8 | 9 | /** 10 | * @addtogroup rsp 11 | * @{ 12 | */ 13 | 14 | /** 15 | * @brief Internal Job structure 16 | */ 17 | typedef struct ijob { 18 | struct ijob *prev; 19 | struct ijob *next; 20 | 21 | void (*cb)(struct ijob *); 22 | 23 | volatile uint32_t state; 24 | uint32_t fn; 25 | uint32_t args[16]; 26 | 27 | } job_t; 28 | 29 | /** 30 | * @brief Job states 31 | */ 32 | #define JOB_STATE_IDLE 0 33 | #define JOB_STATE_QUEUED 1 34 | #define JOB_STATE_RUNNING 2 35 | #define JOB_STATE_FINISHED 3 36 | 37 | /** 38 | * @brief Internal Job Queue structure 39 | */ 40 | typedef struct { 41 | job_t *head; 42 | job_t *tail; 43 | 44 | } job_queue_t; 45 | 46 | /** @} */ 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | /** 53 | * @brief Low Level Functions 54 | */ 55 | uint32_t __rsp_lock( uint32_t wait ); 56 | void __rsp_unlock( void ); 57 | void __rsp_wait_dma( uint32_t busy ); 58 | void __rsp_dma_read( uint32_t offs, void *src, uint32_t len ); 59 | void __rsp_dma_write( uint32_t offs, void *dst, uint32_t len ); 60 | void __rsp_blk_read( uint32_t offs, void *src, uint16_t pitch, uint16_t width, uint16_t height, uint16_t bpp ); 61 | void __rsp_blk_write( uint32_t offs, void *dst, uint16_t pitch, uint16_t width, uint16_t height, uint16_t bpp ); 62 | uint32_t __rsp_get_status( void ); 63 | void __rsp_set_status( uint32_t flags ); 64 | void __rsp_set_pc( uint32_t pc ); 65 | 66 | /** 67 | * @brief High Level Functions 68 | */ 69 | void rsp_init( void ); 70 | void rsp_close( void ); 71 | void rsp_load_lib( uint8_t *lib ); 72 | uint32_t rsp_lib_fn( char *mod, uint32_t fn ); 73 | void rsp_queue_job( job_t *job ); 74 | void rsp_do_job( job_t *job ); 75 | void rsp_wait_job( job_t *job ); 76 | void rsp_abort_job( job_t *job ); 77 | job_t *rsp_new_job( uint32_t fn, void (*cb)(job_t *), uint32_t count, ... ); 78 | void rsp_dispose_job( job_t *job ); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/mempak.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mempak.h 3 | * @brief Mempak Filesystem Routines 4 | * @ingroup mempak 5 | */ 6 | #ifndef __LIBDRAGON_MEMPAK_H 7 | #define __LIBDRAGON_MEMPAK_H 8 | 9 | /** 10 | * @addtogroup mempak 11 | * @{ 12 | */ 13 | 14 | /** @brief Size in bytes of a Mempak block */ 15 | #define MEMPAK_BLOCK_SIZE 256 16 | 17 | /** 18 | * @brief Structure representing a save entry in a mempak 19 | */ 20 | typedef struct entry_structure 21 | { 22 | /** @brief Vendor ID */ 23 | uint32_t vendor; 24 | /** @brief Game ID */ 25 | uint16_t game_id; 26 | /** @brief Inode pointer */ 27 | uint16_t inode; 28 | /** @brief Intended region */ 29 | uint8_t region; 30 | /** @brief Number of blocks used by this entry. 31 | * @see MEMPAK_BLOCK_SIZE */ 32 | uint8_t blocks; 33 | /** @brief Validity of this entry. */ 34 | uint8_t valid; 35 | /** @brief ID of this entry */ 36 | uint8_t entry_id; 37 | /** 38 | * @brief Name of this entry 39 | * 40 | * The complete list of valid ASCII characters in a note name is: 41 | * 42 | *
43 |      * ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#`*+,-./:=?\@
44 |      * 
45 | * 46 | * The space character is also allowed. Any other character will be 47 | * converted to a space before writing to the mempak. 48 | * 49 | * @see #__n64_to_ascii and #__ascii_to_n64 50 | */ 51 | char name[19]; 52 | } entry_structure_t; 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | int read_mempak_sector( int controller, int sector, uint8_t *sector_data ); 59 | int write_mempak_sector( int controller, int sector, uint8_t *sector_data ); 60 | int validate_mempak( int controller ); 61 | int get_mempak_free_space( int controller ); 62 | int get_mempak_entry( int controller, int entry, entry_structure_t *entry_data ); 63 | int format_mempak( int controller ); 64 | int read_mempak_entry_data( int controller, entry_structure_t *entry, uint8_t *data ); 65 | int write_mempak_entry_data( int controller, entry_structure_t *entry, uint8_t *data ); 66 | int delete_mempak_entry( int controller, entry_structure_t *entry ); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | /** @} */ /* mempak */ 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /include/dfsinternal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dfsinternal.h 3 | * @brief Internal DFS Definitions 4 | * @ingroup dfs 5 | */ 6 | #ifndef __LIBDRAGON_DFSINTERNAL_H 7 | #define __LIBDRAGON_DFSINTERNAL_H 8 | 9 | /** 10 | * @addtogroup dfs 11 | * @{ 12 | */ 13 | 14 | /** @brief The special ID value in #directory_entry::flags defining the master sector */ 15 | #define FLAGS_ID 0xFFFFFFFF 16 | /** @brief The special ID value in #directory_entry::next_entry defining the master sector */ 17 | #define NEXTENTRY_ID 0xDEADBEEF 18 | 19 | /** @brief The size of a sector */ 20 | #define SECTOR_SIZE 256 21 | /** @brief The size of a sector payload */ 22 | #define SECTOR_PAYLOAD 252 23 | 24 | /** @brief Representation of a directory entry */ 25 | struct directory_entry 26 | { 27 | /** @brief File size and flags. See #FLAGS_FILE, #FLAGS_DIR and #FLAGS_EOF */ 28 | uint32_t flags; 29 | /** @brief Offset to next directory entry */ 30 | uint32_t next_entry; 31 | /** @brief The file or directory name */ 32 | char path[MAX_FILENAME_LEN+1]; 33 | /** @brief Offset to start sector of the file */ 34 | uint32_t file_pointer; 35 | } __attribute__((__packed__)); 36 | 37 | /** @brief Type definition */ 38 | typedef struct directory_entry directory_entry_t; 39 | 40 | /** @brief Representation of a file sector */ 41 | struct file_entry 42 | { 43 | /** @brief Offset of next sector of the file */ 44 | uint32_t next_sector; 45 | /** @brief File data */ 46 | uint8_t data[SECTOR_PAYLOAD]; 47 | } __attribute__((__packed__)); 48 | 49 | /** @brief Type definition */ 50 | typedef struct file_entry file_entry_t; 51 | 52 | /** @brief Open file handle structure */ 53 | typedef struct open_file 54 | { 55 | /** @brief Cached copy of the current sector */ 56 | file_entry_t cur_sector; 57 | /** @brief Pointer to the first sector */ 58 | file_entry_t *start_sector; 59 | /** @brief The unique file handle to refer to this file by */ 60 | uint32_t handle; 61 | /** @brief The size in bytes of this file */ 62 | uint32_t size; 63 | /** @brief The offset of the current location in the file */ 64 | uint32_t loc; 65 | /** @brief The sector number of the current sector */ 66 | uint32_t sector_number; 67 | /** 68 | * @brief Padding 69 | * 70 | * If this isn't here, the second file opened will fail due to cur_sector 71 | * not being on a 8 byte aligned boundary, so I just aligned it to 512 72 | * bytes. 73 | */ 74 | uint8_t padding[236]; 75 | } open_file_t; 76 | 77 | /** @} */ /* dfs */ 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/entrypoint_2.S: -------------------------------------------------------------------------------- 1 | /* 2 | * N64 init code for GNU as 3 | */ 4 | 5 | #include "regs.S" 6 | 7 | .section .boot 8 | .global _start 9 | _start: 10 | lw t0, 0x80000318 /* memory size */ 11 | li t1, 0x7FFFFFF0 12 | addu sp,t0,t1 /* init stack */ 13 | la gp, _gp /* init data pointer */ 14 | li v0, 8 15 | sw v0,(0xbfc007fc) /* magic N64 hardware init */ 16 | 17 | /* a bit from libgloss so we start at a known state */ 18 | li v0,SR_CU1|SR_PE|SR_FR|SR_KX|SR_SX|SR_UX 19 | mtc0 v0,C0_SR 20 | mtc0 $0,C0_CAUSE 21 | 22 | /* copy code and data */ 23 | la a0, __text_start 24 | la a1, __data_end 25 | subu a2,a0,0x80000400 /* skip over .boot section */ 26 | addu a2,a2,0xB0001000 /* address in rom */ 27 | data_init: 28 | lw t0,(a2) 29 | addiu a2,4 30 | sw t0,(a0) 31 | addiu a0,4 32 | bltu a0,a1, data_init 33 | nop 34 | 35 | /* make sure code and data are actually written */ 36 | la a0,__text_start 37 | la a1,__data_end 38 | sub a1,a0 39 | jal data_cache_hit_writeback_invalidate 40 | nop 41 | 42 | /* fill .sbss with 0s */ 43 | la a0, __sbss_start 44 | la a1, __sbss_end 45 | sbss_init: 46 | sd $0,(a0) 47 | addiu a0,8 48 | bltu a0,a1, sbss_init 49 | nop 50 | 51 | /* make sure .sbss is actually written */ 52 | la a0,__sbss_start 53 | la a1,__sbss_end 54 | sub a1,a0 55 | jal data_cache_hit_writeback_invalidate 56 | nop 57 | 58 | /* fill .bss with 0s */ 59 | la a0, __bss_start 60 | la a1, __bss_end 61 | bss_init: 62 | sd $0,(a0) 63 | addiu a0,8 64 | bltu a0,a1, bss_init 65 | nop 66 | 67 | /* make sure .bss is actually written */ 68 | la a0,__bss_start 69 | la a1,__bss_end 70 | sub a1,a0 71 | jal data_cache_hit_writeback_invalidate 72 | nop 73 | 74 | /* load interrupt vector */ 75 | la t0,intvector 76 | la t1,0xa0000000 77 | la t2,4 78 | loadintvectorloop: 79 | lw t3,(t0) 80 | sw t3,0(t1) 81 | sw t3,0x80(t1) 82 | sw t3,0x100(t1) 83 | sw t3,0x180(t1) 84 | /* sync */ 85 | cache HIT_INVALIDATE_I,0(t1) 86 | cache HIT_INVALIDATE_I,0x80(t1) 87 | cache HIT_INVALIDATE_I,0x100(t1) 88 | cache HIT_INVALIDATE_I,0x180(t1) 89 | addi t0,4 90 | addi t1,4 91 | addiu t2,-1 92 | bnez t2,loadintvectorloop 93 | nop 94 | 95 | jal __do_global_ctors /* call global constructors */ 96 | nop 97 | jal main /* call main app */ 98 | nop 99 | 100 | deadloop: 101 | j deadloop 102 | nop 103 | 104 | intvector: 105 | la k1,inthandler 106 | jr k1 107 | nop 108 | 109 | .section .data 110 | .global __dso_handle 111 | .weak __dso_handle 112 | __dso_handle: 113 | .long 0 114 | -------------------------------------------------------------------------------- /include/dragonfs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dragonfs.h 3 | * @brief DragonFS 4 | * @ingroup dfs 5 | */ 6 | #ifndef __LIBDRAGON_DRAGONFS_H 7 | #define __LIBDRAGON_DRAGONFS_H 8 | 9 | /** 10 | * @addtogroup dfs 11 | * @{ 12 | */ 13 | 14 | /** 15 | * @brief Default filesystem location 16 | * 17 | * The default is 1MB into the ROM space, plus the header offset 18 | */ 19 | #define DFS_DEFAULT_LOCATION 0xB0101000 20 | 21 | /** 22 | * @brief Maximum open files in DragonFS 23 | */ 24 | #define MAX_OPEN_FILES 4 25 | 26 | /** 27 | * @brief Maximum filename length 28 | * 29 | * This value is due to the direcory structure 30 | */ 31 | #define MAX_FILENAME_LEN 243 32 | 33 | /** 34 | * @brief Maximum depth of directories supported 35 | */ 36 | #define MAX_DIRECTORY_DEPTH 100 37 | 38 | /** 39 | * @name DragonFS Return values 40 | * @{ 41 | */ 42 | /** @brief Success */ 43 | #define DFS_ESUCCESS 0 44 | /** @brief Input parameters invalid */ 45 | #define DFS_EBADINPUT -1 46 | /** @brief File does not exist */ 47 | #define DFS_ENOFILE -2 48 | /** @brief Bad filesystem */ 49 | #define DFS_EBADFS -3 50 | /** @brief No memory for operation */ 51 | #define DFS_ENOMEM -4 52 | /** @brief Invalid file handle */ 53 | #define DFS_EBADHANDLE -5 54 | /** @} */ 55 | 56 | /** 57 | * @brief Macro to extract the file type from a DragonFS file flag 58 | * 59 | * @param[in] x 60 | * File flags from DFS entry 61 | * 62 | * @return The file type flag 63 | */ 64 | #define FILETYPE(x) ((x) & 3) 65 | 66 | /** 67 | * @name DragonFS file type flags 68 | * @{ 69 | */ 70 | /** @brief This is a file entry */ 71 | #define FLAGS_FILE 0x0 72 | /** @brief This is a directory entry */ 73 | #define FLAGS_DIR 0x1 74 | /** @brief This is the end of a directory list */ 75 | #define FLAGS_EOF 0x2 76 | /** @} */ 77 | 78 | /** @} */ 79 | 80 | #ifdef __cplusplus 81 | extern "C" { 82 | #endif 83 | 84 | int dfs_init(uint32_t base_fs_loc); 85 | int dfs_chdir(const char * const path); 86 | int dfs_dir_findfirst(const char * const path, char *buf); 87 | int dfs_dir_findnext(char *buf); 88 | 89 | int dfs_open(const char * const path); 90 | int dfs_read(void * const buf, int size, int count, uint32_t handle); 91 | int dfs_seek(uint32_t handle, int offset, int origin); 92 | int dfs_tell(uint32_t handle); 93 | int dfs_close(uint32_t handle); 94 | int dfs_eof(uint32_t handle); 95 | int dfs_size(uint32_t handle); 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /include/libdragon.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file libdragon.h 3 | * @brief Main include file for programs seeking to link against libdragon 4 | * @ingroup libdragon 5 | */ 6 | #ifndef __LIBDRAGON_LIBDRAGON_H 7 | #define __LIBDRAGON_LIBDRAGON_H 8 | 9 | /** 10 | * @defgroup libdragon libdragon 11 | * @brief Low level runtime for homebrew development on the N64 platform. 12 | * 13 | * libdragon handles the hardware interfaces to the various systems in the N64. 14 | * The audio interface is handled by the @ref audio. The controller interface, 15 | * controller peripheral interface and EEPROM interface are handled by the 16 | * @ref controller. The display interface and RDP rasterizer are handled by 17 | * the @ref display. System timers are handled by the @ref timer. 18 | * Low level interfaces such as interrupts, caching operations, exceptions and 19 | * the DMA controller are handled by the @ref lowlevel. 20 | * 21 | * libdragon makes every effort to be self-sufficient and self-configured. However, 22 | * when operating in unexpected environments such as with a non-6102 CIC, additional 23 | * setup may be required. Please see the documentation for #sys_set_boot_cic to 24 | * inform libdragon of a nonstandard CIC. 25 | */ 26 | 27 | /** 28 | * @mainpage libdragon 29 | * @author Shaun Taylor 30 | * 31 | * libdragon provides a low level API for all hardware features of the N64. 32 | * Currently, it provides basic console support, rudimentary higher level controller functions, 33 | * a read only filesystem for appending data to the end of a rom, audio support and some 2D graphics 34 | * functionality. It also includes bindings to newlib in order to provide a posix interface 35 | * to filesystems. 36 | * 37 | * libdragon is currently made up of three core components: the @ref libdragon library, @ref system and 38 | * @ref dfs. The core library provides drivers for each hardware component in the N64 and low level API 39 | * for interacting with the components. The system hooks provide a translation layer between libdragon 40 | * and newlib for the purpose of POSIX compatibility. DragonFS provides the read only filesystem support 41 | * and is hooked into newlib using the system hooks. 42 | * 43 | * Please see the documentation in individual modules for additional information. 44 | */ 45 | 46 | /* Easy include wrapper */ 47 | #include "audio.h" 48 | #include "console.h" 49 | #include "controller.h" 50 | #include "mempak.h" 51 | #include "display.h" 52 | #include "dma.h" 53 | #include "dragonfs.h" 54 | #include "graphics.h" 55 | #include "interrupt.h" 56 | #include "n64sys.h" 57 | #include "rdp.h" 58 | #include "timer.h" 59 | #include "exception.h" 60 | #include "dir.h" 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/graphics.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file graphics.h 3 | * @brief 2D Graphics 4 | * @ingroup graphics 5 | */ 6 | #ifndef __LIBDRAGON_GRAPHICS_H 7 | #define __LIBDRAGON_GRAPHICS_H 8 | 9 | #include "display.h" 10 | 11 | /** 12 | * @addtogroup graphics 13 | * @{ 14 | */ 15 | 16 | /** @brief Generic color structure */ 17 | typedef struct 18 | { 19 | /** @brief Red component */ 20 | uint8_t r; 21 | /** @brief Green component */ 22 | uint8_t g; 23 | /** @brief Blue component */ 24 | uint8_t b; 25 | /** @brief Alpha component */ 26 | uint8_t a; 27 | } color_t; 28 | 29 | /** @brief Sprite structure */ 30 | typedef struct 31 | { 32 | /** @brief Width in pixels */ 33 | uint16_t width; 34 | /** @brief Height in pixels */ 35 | uint16_t height; 36 | /** 37 | * @brief Bit depth expressed in bytes 38 | * 39 | * A 32 bit sprite would have a value of '4' here 40 | */ 41 | uint8_t bitdepth; 42 | /** 43 | * @brief Sprite format 44 | * @note Currently unused 45 | */ 46 | uint8_t format; 47 | /** @brief Number of horizontal slices for spritemaps */ 48 | uint8_t hslices; 49 | /** @brief Number of vertical slices for spritemaps */ 50 | uint8_t vslices; 51 | 52 | /** @brief Start of graphics data */ 53 | uint32_t data[0]; 54 | } sprite_t; 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | uint32_t graphics_make_color( int r, int g, int b, int a ); 61 | uint32_t graphics_convert_color( color_t color ); 62 | void graphics_draw_pixel( display_context_t disp, int x, int y, uint32_t c ); 63 | void graphics_draw_pixel_trans( display_context_t disp, int x, int y, uint32_t c ); 64 | void graphics_draw_line( display_context_t disp, int x0, int y0, int x1, int y1, uint32_t c ); 65 | void graphics_draw_line_trans( display_context_t disp, int x0, int y0, int x1, int y1, uint32_t c ); 66 | void graphics_draw_box( display_context_t disp, int x, int y, int width, int height, uint32_t color ); 67 | void graphics_draw_box_trans( display_context_t disp, int x, int y, int width, int height, uint32_t color ); 68 | void graphics_fill_screen( display_context_t disp, uint32_t c ); 69 | void graphics_set_color( uint32_t forecolor, uint32_t backcolor ); 70 | void graphics_draw_character( display_context_t disp, int x, int y, char c ); 71 | void graphics_draw_text( display_context_t disp, int x, int y, const char * const msg ); 72 | void graphics_draw_sprite( display_context_t disp, int x, int y, sprite_t *sprite ); 73 | void graphics_draw_sprite_stride( display_context_t disp, int x, int y, sprite_t *sprite, int offset ); 74 | void graphics_draw_sprite_trans( display_context_t disp, int x, int y, sprite_t *sprite ); 75 | void graphics_draw_sprite_trans_stride( display_context_t disp, int x, int y, sprite_t *sprite, int offset ); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | /** @} */ /* graphics */ 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/exception.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file exception.c 3 | * @brief Exception Handler 4 | * @ingroup exceptions 5 | */ 6 | #include "exception.h" 7 | #include 8 | 9 | /** 10 | * @defgroup exceptions Exception Handler 11 | * @ingroup lowlevel 12 | * @brief Handle hardware-generated exceptions. 13 | * 14 | * The exception handler traps exceptions generated by hardware. This could 15 | * be an invalid instruction or invalid memory access exception or it could 16 | * be a reset exception. In both cases, a handler registered with 17 | * #register_exception_handler will be passed information regarding the 18 | * exception type and relevant registers. 19 | * 20 | * @{ 21 | */ 22 | 23 | /** @brief Exception handler currently registered with exception system */ 24 | static void (*__exception_handler)(exception_t*) = NULL; 25 | /** @brief Base register offset as defined by the interrupt controller */ 26 | extern const unsigned char* __baseRegAddr; 27 | 28 | /** 29 | * @brief Register an exception handler to handle exceptions 30 | * 31 | * @param[in] cb 32 | * Callback function to call when exceptions happen 33 | */ 34 | void register_exception_handler( void (*cb)(exception_t*)) 35 | { 36 | __exception_handler = cb; 37 | } 38 | 39 | /** 40 | * @brief Fetch the string name of the exception 41 | * 42 | * @todo Implement exceptionMap, then calculate the offset 43 | * 44 | * @param[in] etype 45 | * Exception type 46 | * 47 | * @return String representation of the exception 48 | */ 49 | static const char* __get_exception_name(uint32_t etype) 50 | { 51 | static const char* exceptionMap[] = 52 | { 53 | "Exception infomap not implemented", 54 | NULL, 55 | }; 56 | 57 | etype = 0; 58 | 59 | return exceptionMap[(int32_t)etype]; 60 | } 61 | 62 | /** 63 | * @brief Fetch relevant registers 64 | * 65 | * @param[out] e 66 | * Pointer to structure describing the exception 67 | * @param[in] type 68 | * Exception type. Either #EXCEPTION_TYPE_CRITICAL or 69 | * #EXCEPTION_TYPE_RESET 70 | */ 71 | static void __fetch_regs(exception_t* e,int32_t type) 72 | { 73 | e->regs = (volatile const reg_block_t*) __baseRegAddr; 74 | e->type = type; 75 | e->info = __get_exception_name((uint32_t)e->regs->gpr[30]); 76 | } 77 | 78 | /** 79 | * @brief Respond to a critical exception 80 | */ 81 | void __onCriticalException() 82 | { 83 | exception_t e; 84 | 85 | if(!__exception_handler) { return; } 86 | 87 | __fetch_regs(&e,EXCEPTION_TYPE_CRITICAL); 88 | __exception_handler(&e); 89 | } 90 | 91 | /** 92 | * @brief Respond to a reset exception 93 | */ 94 | void __onResetException() 95 | { 96 | exception_t e; 97 | 98 | if(!__exception_handler) { return; } 99 | 100 | __fetch_regs(&e,EXCEPTION_TYPE_RESET); 101 | __exception_handler(&e); 102 | } 103 | 104 | /** @} */ 105 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file timer.h 3 | * @brief Timer Subsystem 4 | * @ingroup timer 5 | */ 6 | #ifndef __LIBDRAGON_TIMER_H 7 | #define __LIBDRAGON_TIMER_H 8 | 9 | /** 10 | * @addtogroup timer 11 | * @{ 12 | */ 13 | 14 | /** 15 | * @brief Timer structure 16 | */ 17 | typedef struct timer_link 18 | { 19 | /** @brief Ticks left until callback */ 20 | int left; 21 | /** @brief Ticks to set if continuous */ 22 | int set; 23 | /** @brief To correct for drift */ 24 | int ovfl; 25 | /** @brief Timer flags. See #TF_ONE_SHOT and #TF_CONTINUOUS */ 26 | int flags; 27 | /** @brief Callback function to call when timer fires */ 28 | void (*callback)(int ovfl); 29 | /** @brief Link to next timer */ 30 | struct timer_link *next; 31 | } timer_link_t; 32 | 33 | /** @brief Timer should fire only once */ 34 | #define TF_ONE_SHOT 0 35 | /** @brief Timer should fire at a regular interval */ 36 | #define TF_CONTINUOUS 1 37 | 38 | /** 39 | * @brief Calculate timer ticks based on microseconds 40 | * 41 | * @param[in] us 42 | * Microseconds to convert to ticks 43 | * 44 | * @return Timer ticks 45 | */ 46 | #define TIMER_TICKS(us) ((int)((long long)(us) * 46875LL / 1000LL)) 47 | /** 48 | * @brief Calculate microseconds based on timer ticks 49 | * 50 | * @param[in] tk 51 | * Ticks to convert to microseconds 52 | * 53 | * @return Microseconds 54 | */ 55 | #define TIMER_MICROS(tk) ((int)((long long)(tk) * 1000LL / 46875LL)) 56 | 57 | /** 58 | * @brief Calculate timer ticks based on microseconds 59 | * 60 | * @param[in] us 61 | * Microseconds to convert to ticks 62 | * 63 | * @return Timer ticks as a long long 64 | */ 65 | #define TIMER_TICKS_LL(us) ((long long)(us) * 46875LL / 1000LL) 66 | /** 67 | * @brief Calculate microseconds based on timer ticks 68 | * 69 | * @param[in] tk 70 | * Ticks to convert to microseconds 71 | * 72 | * @return Microseconds as a long long 73 | */ 74 | #define TIMER_MICROS_LL(tk) ((long long)(tk) * 1000LL / 46875LL) 75 | 76 | /** @} */ 77 | 78 | #ifdef __cplusplus 79 | extern "C" { 80 | #endif 81 | 82 | /* initialize timer subsystem */ 83 | void timer_init(void); 84 | /* create a new timer and add to list */ 85 | timer_link_t *new_timer(int ticks, int flags, void (*callback)(int ovfl)); 86 | /* start a timer not currently in the list */ 87 | void start_timer(timer_link_t *timer, int ticks, int flags, void (*callback)(int ovfl)); 88 | /* remove a timer from the list */ 89 | void stop_timer(timer_link_t *timer); 90 | /* remove a timer from the list and delete it */ 91 | void delete_timer(timer_link_t *timer); 92 | /* delete all timers in list */ 93 | void timer_close(void); 94 | /* return total ticks since timer was initialized */ 95 | long long timer_ticks(void); 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /tools/build: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # N64 toolchain install script for Unix distributions by Shaun Taylor. 3 | # Tested working on Ubuntu 9.04 ia32 and Debian sparc64. 4 | 5 | # You may be prompted for your password for installation steps. 6 | # If the script tells you that writing failed on chksum64 and n64tool, 7 | # this does not mean it failed. The script simply retried with sudo 8 | # and your password was cached. 9 | 10 | # Before calling this script, make sure you have GMP, MPFR and TexInfo 11 | # packages installed in your system. On a Debian-based system this is 12 | # achieved by typing the following commands: 13 | # 14 | # sudo apt-get install libmpfr-dev 15 | # sudo apt-get install texinfo 16 | 17 | # Exit on error 18 | set -e 19 | 20 | # EDIT THIS LINE TO CHANGE YOUR INSTALL PATH! 21 | export INSTALL_PATH=${N64_INST:-/usr/local} 22 | 23 | # Set up path for newlib to compile later 24 | export PATH=$PATH:$INSTALL_PATH/bin 25 | 26 | # Versions 27 | export BINUTILS_V=2.27 28 | export GCC_V=6.2.0 29 | export NEWLIB_V=2.4.0 30 | 31 | # Download stage 32 | wget -c ftp://sourceware.org/pub/binutils/releases/binutils-$BINUTILS_V.tar.bz2 33 | wget -c ftp://sourceware.org/pub/gcc/releases/gcc-$GCC_V/gcc-$GCC_V.tar.bz2 34 | wget -c ftp://sourceware.org/pub/newlib/newlib-$NEWLIB_V.tar.gz 35 | 36 | # Extract stage 37 | test -d binutils-$BINUTILS_V || tar -xvjf binutils-$BINUTILS_V.tar.bz2 38 | test -d gcc-$GCC_V || tar -xvjf gcc-$GCC_V.tar.bz2 39 | test -d newlib-$NEWLIB_V || tar -xvzf newlib-$NEWLIB_V.tar.gz 40 | 41 | # Binutils and newlib support compiling in source directory, GCC does not 42 | rm -rf gcc_compile 43 | mkdir gcc_compile 44 | 45 | # Compile binutils 46 | cd binutils-$BINUTILS_V 47 | ./configure --prefix=${INSTALL_PATH} --target=mips64-elf --with-cpu=mips64vr4300 --disable-werror 48 | make 49 | make install || sudo make install || su -c "make install" 50 | 51 | # Compile gcc (pass 1) 52 | cd ../gcc_compile 53 | ../gcc-$GCC_V/configure --prefix=${INSTALL_PATH} --target=mips64-elf --enable-languages=c --without-headers --with-newlib --disable-libssp --enable-multilib --disable-shared --with-gcc --with-gnu-ld --with-gnu-as --disable-threads --disable-win32-registry --disable-nls --disable-debug --disable-libmudflap --disable-werror 54 | make 55 | make install || sudo make install || su -c "make install" 56 | 57 | # Compile newlib 58 | cd ../newlib-$NEWLIB_V 59 | CFLAGS="-O2" CXXFLAGS="-O2" ./configure --target=mips64-elf --prefix=${INSTALL_PATH} --with-cpu=mips64vr4300 --disable-threads --disable-libssp --disable-werror 60 | make 61 | make install || sudo env PATH="$PATH" make install || su -c "env PATH=$PATH make install" 62 | 63 | # Compile gcc (pass 2) 64 | cd .. 65 | rm -rf gcc_compile 66 | mkdir gcc_compile 67 | cd gcc_compile 68 | CFLAGS_FOR_TARGET="-G0 -O2" CXXFLAGS_FOR_TARGET="-G0 -O2" ../gcc-$GCC_V/configure --prefix=${INSTALL_PATH} --target=mips64-elf --enable-languages=c,c++ --with-newlib --disable-libssp --enable-multilib --disable-shared --with-gcc --with-gnu-ld --with-gnu-as --disable-threads --disable-win32-registry --disable-nls --disable-debug --disable-libmudflap 69 | make 70 | make install || sudo make install || su -c "make install" 71 | -------------------------------------------------------------------------------- /n64ld_cpp.x: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * 3 | * n64ld.x 4 | * 5 | * GNU Linker script for building an image that is set up for the N64 6 | * but still has the data factored into sections. It is not directly 7 | * runnable, and it contains the debug info if available. It will need 8 | * a 'loader' to perform the final stage of transformation to produce 9 | * a raw image. 10 | * 11 | * Copyright (c) 1999 Ground Zero Development, All rights reserved. 12 | * Developed by Frank Somers 13 | * Modifications by hcs (halleyscometsoftware@hotmail.com) 14 | * 15 | * $Header: /afs/icequake.net/users/nemesis/n64/sf/asdf/n64dev/lib/alt-libn64/n64ld.x,v 1.2 2006-08-11 15:54:11 halleyscometsw Exp $ 16 | * 17 | * ======================================================================== 18 | */ 19 | 20 | OUTPUT_FORMAT ("elf32-bigmips", "elf32-bigmips", "elf32-littlemips") 21 | OUTPUT_ARCH (mips) 22 | EXTERN (_start) 23 | ENTRY (_start) 24 | 25 | MEMORY 26 | { 27 | mem : ORIGIN = 0x80000400, LENGTH = 4M-0x0400 28 | } 29 | 30 | SECTIONS { 31 | . = 0x80000400; 32 | 33 | .text : { 34 | *(.boot) 35 | . = ALIGN(16); 36 | __text_start = . ; 37 | *(.text) 38 | *(.text.*) 39 | *(.init) 40 | *(.fini) 41 | *(.gnu.linkonce.t.*) 42 | __text_end = . ; 43 | } > mem 44 | 45 | .eh_frame_hdr : { *(.eh_frame_hdr) } > mem 46 | .eh_frame : { KEEP (*(.eh_frame)) } > mem 47 | .gcc_except_table : { *(.gcc_except_table*) } > mem 48 | .jcr : { KEEP (*(.jcr)) } > mem 49 | 50 | .rodata : { 51 | *(.rdata) 52 | *(.rodata) 53 | *(.rodata.*) 54 | *(.gnu.linkonce.r.*) 55 | } > mem 56 | 57 | .ctors : { 58 | . = ALIGN(8); 59 | __CTOR_LIST_SIZE__ = .; 60 | LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 1) 61 | __CTOR_LIST__ = .; 62 | *(.ctors) 63 | LONG(0) 64 | __CTOR_END__ = .; 65 | } > mem 66 | 67 | .dtors : { 68 | __DTOR_LIST__ = .; 69 | LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) 70 | *(.dtors) 71 | LONG(0) 72 | __DTOR_END__ = .; 73 | } > mem 74 | 75 | .data : { 76 | . = ALIGN(8); 77 | __data_start = . ; 78 | *(.data) 79 | *(.data.*) 80 | *(.gnu.linkonce.d.*) 81 | } > mem 82 | 83 | . = ALIGN(16); 84 | _gp = . + 0x8000; 85 | 86 | .got : { 87 | *(.got.plt) 88 | *(.got) 89 | } > mem 90 | 91 | .sdata : { 92 | *(.sdata) 93 | *(.sdata.*) 94 | *(.gnu.linkonce.s.*) 95 | } > mem 96 | 97 | .lit8 : { 98 | *(.lit8) 99 | } > mem 100 | .lit4 : { 101 | *(.lit4) 102 | } > mem 103 | __data_end = . ; 104 | 105 | . = ALIGN(4); 106 | .sbss (NOLOAD) : { 107 | __sbss_start = . ; 108 | *(.sbss) 109 | *(.sbss.*) 110 | *(.gnu.linkonce.sb.*) 111 | *(.scommon) 112 | __sbss_end = . ; 113 | } > mem 114 | 115 | . = ALIGN(4); 116 | .bss (NOLOAD) : { 117 | __bss_start = . ; 118 | *(.bss) 119 | *(.bss*) 120 | *(.gnu.linkonce.b.*) 121 | *(COMMON) 122 | __bss_end = . ; 123 | } > mem 124 | 125 | . = ALIGN(8); 126 | end = .; 127 | } 128 | -------------------------------------------------------------------------------- /n64ld_exp_cpp.x: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * 3 | * n64ld.x 4 | * 5 | * GNU Linker script for building an image that is set up for the N64 6 | * but still has the data factored into sections. It is not directly 7 | * runnable, and it contains the debug info if available. It will need 8 | * a 'loader' to perform the final stage of transformation to produce 9 | * a raw image. 10 | * 11 | * Copyright (c) 1999 Ground Zero Development, All rights reserved. 12 | * Developed by Frank Somers 13 | * Modifications by hcs (halleyscometsoftware@hotmail.com) 14 | * 15 | * $Header: /afs/icequake.net/users/nemesis/n64/sf/asdf/n64dev/lib/alt-libn64/n64ld.x,v 1.2 2006-08-11 15:54:11 halleyscometsw Exp $ 16 | * 17 | * ======================================================================== 18 | */ 19 | 20 | OUTPUT_FORMAT ("elf32-bigmips", "elf32-bigmips", "elf32-littlemips") 21 | OUTPUT_ARCH (mips) 22 | EXTERN (_start) 23 | ENTRY (_start) 24 | 25 | MEMORY 26 | { 27 | mem : ORIGIN = 0x80000400, LENGTH = 8M-0x0400 28 | } 29 | 30 | SECTIONS { 31 | . = 0x80000400; 32 | 33 | .text : { 34 | *(.boot) 35 | . = ALIGN(16); 36 | __text_start = . ; 37 | *(.text) 38 | *(.text.*) 39 | *(.init) 40 | *(.fini) 41 | *(.gnu.linkonce.t.*) 42 | __text_end = . ; 43 | } > mem 44 | 45 | .eh_frame_hdr : { *(.eh_frame_hdr) } > mem 46 | .eh_frame : { KEEP (*(.eh_frame)) } > mem 47 | .gcc_except_table : { *(.gcc_except_table*) } > mem 48 | .jcr : { KEEP (*(.jcr)) } > mem 49 | 50 | .rodata : { 51 | *(.rdata) 52 | *(.rodata) 53 | *(.rodata.*) 54 | *(.gnu.linkonce.r.*) 55 | } > mem 56 | 57 | .ctors : { 58 | . = ALIGN(8); 59 | __CTOR_LIST_SIZE__ = .; 60 | LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 1) 61 | __CTOR_LIST__ = .; 62 | *(.ctors) 63 | LONG(0) 64 | __CTOR_END__ = .; 65 | } > mem 66 | 67 | .dtors : { 68 | __DTOR_LIST__ = .; 69 | LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) 70 | *(.dtors) 71 | LONG(0) 72 | __DTOR_END__ = .; 73 | } > mem 74 | 75 | .data : { 76 | . = ALIGN(8); 77 | __data_start = . ; 78 | *(.data) 79 | *(.data.*) 80 | *(.gnu.linkonce.d.*) 81 | } > mem 82 | 83 | . = ALIGN(16); 84 | _gp = . + 0x8000; 85 | 86 | .got : { 87 | *(.got.plt) 88 | *(.got) 89 | } > mem 90 | 91 | .sdata : { 92 | *(.sdata) 93 | *(.sdata.*) 94 | *(.gnu.linkonce.s.*) 95 | } > mem 96 | 97 | .lit8 : { 98 | *(.lit8) 99 | } > mem 100 | .lit4 : { 101 | *(.lit4) 102 | } > mem 103 | __data_end = . ; 104 | 105 | . = ALIGN(4); 106 | .sbss (NOLOAD) : { 107 | __sbss_start = . ; 108 | *(.sbss) 109 | *(.sbss.*) 110 | *(.gnu.linkonce.sb.*) 111 | *(.scommon) 112 | __sbss_end = . ; 113 | } > mem 114 | 115 | . = ALIGN(4); 116 | .bss (NOLOAD) : { 117 | __bss_start = . ; 118 | *(.bss) 119 | *(.bss*) 120 | *(.gnu.linkonce.b.*) 121 | *(COMMON) 122 | __bss_end = . ; 123 | } > mem 124 | 125 | . = ALIGN(8); 126 | end = .; 127 | } 128 | -------------------------------------------------------------------------------- /n64ld.x: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * 3 | * n64ld.x 4 | * 5 | * GNU Linker script for building an image that is set up for the N64 6 | * but still has the data factored into sections. It is not directly 7 | * runnable, and it contains the debug info if available. It will need 8 | * a 'loader' to perform the final stage of transformation to produce 9 | * a raw image. 10 | * 11 | * Copyright (c) 1999 Ground Zero Development, All rights reserved. 12 | * Developed by Frank Somers 13 | * Modifications by hcs (halleyscometsoftware@hotmail.com) 14 | * 15 | * $Header: /cvsroot/n64dev/n64dev/lib/alt-libn64/n64ld.x,v 1.2 2006/08/11 15:54:11 halleyscometsw Exp $ 16 | * 17 | * ======================================================================== 18 | */ 19 | 20 | OUTPUT_FORMAT ("elf32-bigmips", "elf32-bigmips", "elf32-littlemips") 21 | OUTPUT_ARCH (mips) 22 | EXTERN (_start) 23 | ENTRY (_start) 24 | 25 | SECTIONS { 26 | /* Start address of code is 1K up in uncached, unmapped RAM. We have 27 | * to be at least this far up in order to not interfere with the cart 28 | * boot code which is copying it down from the cart 29 | */ 30 | 31 | . = 0x80000400 ; 32 | 33 | /* The text section carries the app code and its relocation addr is 34 | * the first byte of the cart domain in cached, unmapped memory 35 | */ 36 | 37 | .text : { 38 | FILL (0) 39 | 40 | *(.boot) 41 | . = ALIGN(16); 42 | __text_start = . ; 43 | *(.text) 44 | *(.ctors) 45 | *(.dtors) 46 | *(.rodata) 47 | *(.init) 48 | *(.fini) 49 | __text_end = . ; 50 | } 51 | 52 | 53 | /* Data section has relocation address at start of RAM in cached, 54 | * unmapped memory, but is loaded just at the end of the text segment, 55 | * and must be copied to the correct location at startup 56 | */ 57 | 58 | .data : { 59 | /* Gather all initialised data together. The memory layout 60 | * will place the global initialised data at the lowest addrs. 61 | * The lit8, lit4, sdata and sbss sections have to be placed 62 | * together in that order from low to high addrs with the _gp symbol 63 | * positioned (aligned) at the start of the sdata section. 64 | * We then finish off with the standard bss section 65 | */ 66 | 67 | FILL (0xaa) 68 | 69 | . = ALIGN(16); 70 | __data_start = . ; 71 | *(.data) 72 | *(.lit8) 73 | *(.lit4) ; 74 | /* _gp = ALIGN(16) + 0x7ff0 ;*/ 75 | /* _gp = . + 0x7ff0; */ 76 | . = ALIGN(16); 77 | _gp = . ; 78 | *(.sdata) 79 | __data_end = . ; 80 | /* 81 | __bss_start = . ; 82 | *(.scommon) 83 | *(.sbss) 84 | *(COMMON) 85 | *(.bss) 86 | /* XXX Force 8-byte end alignment and update startup code */ 87 | 88 | __bss_end = . ; 89 | */ 90 | } 91 | 92 | .bss (NOLOAD) : { 93 | __bss_start = . ; 94 | *(.scommon) 95 | *(.sbss) 96 | *(COMMON) 97 | *(.bss) 98 | __bss_end = . ; 99 | end = . ; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ROOTDIR = $(N64_INST) 2 | CFLAGS = -std=gnu99 -O2 -G0 -Wall -Werror -mtune=vr4300 -march=vr4300 -I$(CURDIR)/include -I$(ROOTDIR)/mips64-elf/include 3 | ASFLAGS = -mtune=vr4300 -march=vr4300 4 | N64PREFIX = $(N64_INST)/bin/mips64-elf- 5 | INSTALLDIR = $(N64_INST) 6 | CC = $(N64PREFIX)gcc 7 | AS = $(N64PREFIX)as 8 | LD = $(N64PREFIX)ld 9 | AR = $(N64PREFIX)ar 10 | 11 | all: libdragon 12 | 13 | libdragon: libdragon.a libdragonsys.a libdragonpp.a 14 | 15 | include files.in 16 | 17 | examples: 18 | make -C examples 19 | examples-clean: 20 | make -C examples clean 21 | 22 | doxygen: doxygen.conf 23 | mkdir -p doxygen/ 24 | doxygen doxygen.conf 25 | doxygen-api: doxygen-public.conf 26 | mkdir -p doxygen/ 27 | doxygen doxygen-public.conf 28 | doxygen-clean: 29 | rm -rf $(CURDIR)/doxygen 30 | 31 | tools: 32 | make -C tools 33 | tools-install: 34 | make -C tools install 35 | tools-clean: 36 | make -C tools clean 37 | 38 | libdragon.a: $(OFILES_LD) 39 | $(AR) -rcs -o libdragon.a $(OFILES_LD) 40 | libdragonsys.a: $(OFILES_LDS) 41 | $(AR) -rcs -o libdragonsys.a $(OFILES_LDS) 42 | libdragonpp.a: $(OFILES_LDP) 43 | $(AR) -rcs -o libdragonpp.a $(OFILES_LDP) 44 | 45 | install: libdragon.a libdragonsys.a libdragonpp.a 46 | install -m 0644 libdragon.a $(INSTALLDIR)/mips64-elf/lib/libdragon.a 47 | install -m 0644 n64ld.x $(INSTALLDIR)/mips64-elf/lib/n64ld.x 48 | install -m 0644 n64ld_cpp.x $(INSTALLDIR)/mips64-elf/lib/n64ld_cpp.x 49 | install -m 0644 n64ld_exp_cpp.x $(INSTALLDIR)/mips64-elf/lib/n64ld_exp_cpp.x 50 | install -m 0644 header $(INSTALLDIR)/mips64-elf/lib/header 51 | install -m 0644 libdragonsys.a $(INSTALLDIR)/mips64-elf/lib/libdragonsys.a 52 | install -m 0644 libdragonpp.a $(INSTALLDIR)/mips64-elf/lib/libdragonpp.a 53 | install -m 0644 include/n64sys.h $(INSTALLDIR)/mips64-elf/include/n64sys.h 54 | install -m 0644 include/interrupt.h $(INSTALLDIR)/mips64-elf/include/interrupt.h 55 | install -m 0644 include/dma.h $(INSTALLDIR)/mips64-elf/include/dma.h 56 | install -m 0644 include/dragonfs.h $(INSTALLDIR)/mips64-elf/include/dragonfs.h 57 | install -m 0644 include/audio.h $(INSTALLDIR)/mips64-elf/include/audio.h 58 | install -m 0644 include/display.h $(INSTALLDIR)/mips64-elf/include/display.h 59 | install -m 0644 include/console.h $(INSTALLDIR)/mips64-elf/include/console.h 60 | install -m 0644 include/mempak.h $(INSTALLDIR)/mips64-elf/include/mempak.h 61 | install -m 0644 include/controller.h $(INSTALLDIR)/mips64-elf/include/controller.h 62 | install -m 0644 include/graphics.h $(INSTALLDIR)/mips64-elf/include/graphics.h 63 | install -m 0644 include/rdp.h $(INSTALLDIR)/mips64-elf/include/rdp.h 64 | install -m 0644 include/timer.h $(INSTALLDIR)/mips64-elf/include/timer.h 65 | install -m 0644 include/exception.h $(INSTALLDIR)/mips64-elf/include/exception.h 66 | install -m 0644 include/system.h $(INSTALLDIR)/mips64-elf/include/system.h 67 | install -m 0644 include/dir.h $(INSTALLDIR)/mips64-elf/include/dir.h 68 | install -m 0644 include/libdragon.h $(INSTALLDIR)/mips64-elf/include/libdragon.h 69 | 70 | clean: 71 | rm -f *.o *.a 72 | rm -rf $(CURDIR)/build 73 | 74 | clobber: clean doxygen-clean examples-clean tools-clean 75 | 76 | .PHONY : clobber clean doxygen-clean doxygen doxygen-api examples examples-clean tools tools-clean tools-install 77 | -------------------------------------------------------------------------------- /include/rdp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rdp.h 3 | * @brief Hardware Display Interface 4 | * @ingroup rdp 5 | */ 6 | #ifndef __LIBDRAGON_RDP_H 7 | #define __LIBDRAGON_RDP_H 8 | 9 | #include "display.h" 10 | #include "graphics.h" 11 | 12 | /** 13 | * @addtogroup rdp 14 | * @{ 15 | */ 16 | 17 | /** 18 | * @brief RDP sync operations 19 | */ 20 | typedef enum 21 | { 22 | /** @brief Wait for any operation to complete before causing a DP interrupt */ 23 | SYNC_FULL, 24 | /** @brief Sync the RDP pipeline */ 25 | SYNC_PIPE, 26 | /** @brief Block until all texture load operations are complete */ 27 | SYNC_LOAD, 28 | /** @brief Block until all tile operations are complete */ 29 | SYNC_TILE 30 | } sync_t; 31 | 32 | /** @} */ 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | void rdp_init( void ); 39 | void rdp_attach_display( display_context_t disp ); 40 | void rdp_detach_display( void ); 41 | void rdp_sync( sync_t sync ); 42 | void rdp_set_clipping( uint32_t tx, uint32_t ty, uint32_t bx, uint32_t by ); 43 | void rdp_set_default_clipping( void ); 44 | void rdp_enable_primitive_fill( void ); 45 | void rdp_enable_blend_fill( void ); 46 | void rdp_load_texture( sprite_t *sprite ); 47 | void rdp_draw_textured_rectangle( int tx, int ty, int bx, int by, int flags ); 48 | void rdp_draw_textured_rectangle_scaled( int tx, int ty, int bx, int by, double x_scale, double y_scale, int flags ); 49 | void rdp_draw_sprite( int x, int y, int flags ); 50 | void rdp_draw_sprite_scaled( int x, int y, float x_scale, float y_scale, int flags ); 51 | void rdp_draw_filled_rectangle( int tx, int ty, int bx, int by ); 52 | void rdp_draw_filled_triangle( float x1, float y1, float x2, float y2, float x3, float y3 ); 53 | void rdp_close( void ); 54 | 55 | // RDP new 56 | void rdp_send( void ); 57 | void rdp_command( uint32_t data ); 58 | void rdp_cp_sprite( int x, int y, int flags, int cp_x, int cp_y, int line ); 59 | void rdp_cp_sprite_scaled( int x, int y, float x_scale, float y_scale, int flags, int cp_x, int cp_y, int line ); 60 | void rdp_set_fill_color( uint8_t r, uint8_t g, uint8_t b, uint8_t a ); 61 | void rdp_set_prim_color( uint8_t r, uint8_t g, uint8_t b, uint8_t a ); 62 | void rdp_set_blend_color( uint8_t r, uint8_t g, uint8_t b, uint8_t a ); 63 | void rdp_texture_copy( uint64_t mode ); 64 | void rdp_texture_cycle( uint8_t cycle, uint8_t enable_alpha, uint64_t mode ); 65 | void rdp_load_palette( uint8_t pal, uint8_t col_num, uint16_t *palette ); 66 | void rdp_select_palette( uint8_t pal ); 67 | void rdp_additive( void ); 68 | void rdp_intensify( uint8_t enable_alpha ); 69 | void rdp_color( uint8_t enable_alpha ); 70 | void rdp_noise( uint8_t type, uint8_t enable_alpha ); 71 | void rdp_triangle_setup( int type ); 72 | 73 | // FRAMEBUFFER new 74 | uint32_t get_pixel( display_context_t disp, int x, int y ); 75 | void rdp_buffer_copy( display_context_t disp, uint16_t *buffer_texture, uint16_t x_buf, uint16_t y_buf, uint16_t width, uint16_t height, uint16_t skip ); 76 | void rdp_buffer_screen( display_context_t disp, uint16_t *buffer_texture, int texture_mode ); 77 | void rdp_load_texbuf( uint16_t *buffer_texture, int sh, int th ); 78 | 79 | // LOAD new 80 | sprite_t *load_sprite( const char * const spritename ); 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | 86 | #endif -------------------------------------------------------------------------------- /examples/fire/controls.c: -------------------------------------------------------------------------------- 1 | // KEY 2 | static int8_t dpad_up; 3 | static int8_t dpad_down; 4 | static int8_t dpad_left; 5 | static int8_t dpad_right; 6 | static int8_t a_button; 7 | static int8_t b_button; 8 | static int8_t z_button; 9 | static int8_t l_button; 10 | static int8_t r_button; 11 | static int8_t c_left; 12 | static int8_t c_right; 13 | static int8_t c_down; 14 | static int8_t c_up; 15 | static int8_t start_button; 16 | static int8_t joystick_x; 17 | static int8_t joystick_y; 18 | 19 | void update_controls() 20 | { 21 | 22 | controller_scan(); 23 | struct controller_data keys = get_keys_pressed(); 24 | 25 | // JOYSTICK 26 | joystick_x=keys.c[0].x; 27 | joystick_y=keys.c[0].y; 28 | 29 | // DPAD 30 | dpad_up=0; 31 | dpad_down=0; 32 | dpad_left=0; 33 | dpad_right=0; 34 | 35 | if (keys.c[0].up) 36 | dpad_up=1; 37 | 38 | if (keys.c[0].down) 39 | dpad_down=1; 40 | 41 | if (keys.c[0].left) 42 | dpad_left=1; 43 | 44 | if (keys.c[0].right) 45 | dpad_right=1; 46 | 47 | // A 48 | if (keys.c[0].A) 49 | { 50 | if (a_button==0) 51 | a_button=1; 52 | else 53 | a_button=2; 54 | } 55 | else 56 | a_button=0; 57 | 58 | // B 59 | if (keys.c[0].B) 60 | { 61 | if (b_button==0) 62 | b_button=1; 63 | else 64 | b_button=2; 65 | } 66 | else 67 | b_button=0; 68 | 69 | // Z 70 | if (keys.c[0].Z) 71 | { 72 | if (z_button==0) 73 | z_button=1; 74 | else 75 | z_button=2; 76 | } 77 | else 78 | z_button=0; 79 | 80 | // L 81 | if (keys.c[0].L) 82 | { 83 | if (l_button==0) 84 | l_button=1; 85 | else 86 | l_button=2; 87 | } 88 | else 89 | l_button=0; 90 | 91 | // R 92 | if (keys.c[0].R) 93 | { 94 | if (r_button==0) 95 | r_button=1; 96 | else 97 | r_button=2; 98 | } 99 | else 100 | r_button=0; 101 | 102 | // C-LEFT 103 | if (keys.c[0].C_left) 104 | { 105 | if (c_left==0) 106 | c_left=1; 107 | else 108 | c_left=2; 109 | } 110 | else 111 | c_left=0; 112 | 113 | // C-RIGHT 114 | if (keys.c[0].C_right) 115 | { 116 | if (c_right==0) 117 | c_right=1; 118 | else 119 | c_right=2; 120 | } 121 | else 122 | c_right=0; 123 | 124 | // C-DOWN 125 | if (keys.c[0].C_down) 126 | { 127 | if (c_down==0) 128 | c_down=1; 129 | else 130 | c_down=2; 131 | } 132 | else 133 | c_down=0; 134 | 135 | // C-UP 136 | if (keys.c[0].C_up) 137 | { 138 | if (c_up==0) 139 | c_up=1; 140 | else 141 | c_up=2; 142 | } 143 | else 144 | c_up=0; 145 | 146 | // START 147 | if (keys.c[0].start) 148 | { 149 | if (start_button==0) 150 | start_button=1; 151 | else 152 | start_button=2; 153 | } 154 | else 155 | start_button=0; 156 | 157 | } -------------------------------------------------------------------------------- /examples/tlut/controls.c: -------------------------------------------------------------------------------- 1 | // KEY 2 | static int8_t dpad_up; 3 | static int8_t dpad_down; 4 | static int8_t dpad_left; 5 | static int8_t dpad_right; 6 | static int8_t a_button; 7 | static int8_t b_button; 8 | static int8_t z_button; 9 | static int8_t l_button; 10 | static int8_t r_button; 11 | static int8_t c_left; 12 | static int8_t c_right; 13 | static int8_t c_down; 14 | static int8_t c_up; 15 | static int8_t start_button; 16 | static int8_t joystick_x; 17 | static int8_t joystick_y; 18 | 19 | void update_controls() 20 | { 21 | 22 | controller_scan(); 23 | struct controller_data keys = get_keys_pressed(); 24 | 25 | // JOYSTICK 26 | joystick_x=keys.c[0].x; 27 | joystick_y=keys.c[0].y; 28 | 29 | // DPAD 30 | dpad_up=0; 31 | dpad_down=0; 32 | dpad_left=0; 33 | dpad_right=0; 34 | 35 | if (keys.c[0].up) 36 | dpad_up=1; 37 | 38 | if (keys.c[0].down) 39 | dpad_down=1; 40 | 41 | if (keys.c[0].left) 42 | dpad_left=1; 43 | 44 | if (keys.c[0].right) 45 | dpad_right=1; 46 | 47 | // A 48 | if (keys.c[0].A) 49 | { 50 | if (a_button==0) 51 | a_button=1; 52 | else 53 | a_button=2; 54 | } 55 | else 56 | a_button=0; 57 | 58 | // B 59 | if (keys.c[0].B) 60 | { 61 | if (b_button==0) 62 | b_button=1; 63 | else 64 | b_button=2; 65 | } 66 | else 67 | b_button=0; 68 | 69 | // Z 70 | if (keys.c[0].Z) 71 | { 72 | if (z_button==0) 73 | z_button=1; 74 | else 75 | z_button=2; 76 | } 77 | else 78 | z_button=0; 79 | 80 | // L 81 | if (keys.c[0].L) 82 | { 83 | if (l_button==0) 84 | l_button=1; 85 | else 86 | l_button=2; 87 | } 88 | else 89 | l_button=0; 90 | 91 | // R 92 | if (keys.c[0].R) 93 | { 94 | if (r_button==0) 95 | r_button=1; 96 | else 97 | r_button=2; 98 | } 99 | else 100 | r_button=0; 101 | 102 | // C-LEFT 103 | if (keys.c[0].C_left) 104 | { 105 | if (c_left==0) 106 | c_left=1; 107 | else 108 | c_left=2; 109 | } 110 | else 111 | c_left=0; 112 | 113 | // C-RIGHT 114 | if (keys.c[0].C_right) 115 | { 116 | if (c_right==0) 117 | c_right=1; 118 | else 119 | c_right=2; 120 | } 121 | else 122 | c_right=0; 123 | 124 | // C-DOWN 125 | if (keys.c[0].C_down) 126 | { 127 | if (c_down==0) 128 | c_down=1; 129 | else 130 | c_down=2; 131 | } 132 | else 133 | c_down=0; 134 | 135 | // C-UP 136 | if (keys.c[0].C_up) 137 | { 138 | if (c_up==0) 139 | c_up=1; 140 | else 141 | c_up=2; 142 | } 143 | else 144 | c_up=0; 145 | 146 | // START 147 | if (keys.c[0].start) 148 | { 149 | if (start_button==0) 150 | start_button=1; 151 | else 152 | start_button=2; 153 | } 154 | else 155 | start_button=0; 156 | 157 | } -------------------------------------------------------------------------------- /include/n64sys.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file n64sys.h 3 | * @brief N64 System Interface 4 | * @ingroup n64sys 5 | */ 6 | #ifndef __LIBDRAGON_N64SYS_H 7 | #define __LIBDRAGON_N64SYS_H 8 | 9 | /** 10 | * @addtogroup n64sys 11 | * @{ 12 | */ 13 | 14 | /** 15 | * @brief Return the uncached memory address for a given address 16 | * 17 | * @param[in] _addr 18 | * Address in RAM to convert to an uncached address 19 | * 20 | * @return A void pointer to the uncached memory address in RAM 21 | */ 22 | #define UncachedAddr(_addr) ((void *)(((unsigned long)(_addr))|0x20000000)) 23 | 24 | /** 25 | * @brief Return the uncached memory address for a given address 26 | * 27 | * @param[in] _addr 28 | * Address in RAM to convert to an uncached address 29 | * 30 | * @return A short pointer to the uncached memory address in RAM 31 | */ 32 | #define UncachedShortAddr(_addr) ((short *)(((unsigned long)(_addr))|0x20000000)) 33 | 34 | /** 35 | * @brief Return the uncached memory address for a given address 36 | * 37 | * @param[in] _addr 38 | * Address in RAM to convert to an uncached address 39 | * 40 | * @return An unsigned short pointer to the uncached memory address in RAM 41 | */ 42 | #define UncachedUShortAddr(_addr) ((unsigned short *)(((unsigned long)(_addr))|0x20000000)) 43 | 44 | /** 45 | * @brief Return the uncached memory address for a given address 46 | * 47 | * @param[in] _addr 48 | * Address in RAM to convert to an uncached address 49 | * 50 | * @return A long pointer to the uncached memory address in RAM 51 | */ 52 | #define UncachedLongAddr(_addr) ((long *)(((unsigned long)(_addr))|0x20000000)) 53 | 54 | /** 55 | * @brief Return the uncached memory address for a given address 56 | * 57 | * @param[in] _addr 58 | * Address in RAM to convert to an uncached address 59 | * 60 | * @return An unsigned long pointer to the uncached memory address in RAM 61 | */ 62 | #define UncachedULongAddr(_addr) ((unsigned long *)(((unsigned long)(_addr))|0x20000000)) 63 | 64 | /** 65 | * @brief Return the cached memory address for a given address 66 | * 67 | * @param[in] _addr 68 | * Address in RAM to convert to a cached address 69 | * 70 | * @return A void pointer to the cached memory address in RAM 71 | */ 72 | #define CachedAddr(_addr) (((void *)(((unsigned long)(_addr))&~0x20000000)) 73 | 74 | /** 75 | * @brief Memory barrier to ensure in-order execution 76 | * 77 | * Since GCC seems to reorder volatile at -O2, a memory barrier is required 78 | * to ensure that DMA setup is done in the correct order. Otherwise, the 79 | * library is useless at higher optimization levels. 80 | */ 81 | #define MEMORY_BARRIER() asm volatile ("" : : : "memory") 82 | 83 | #ifdef __cplusplus 84 | extern "C" { 85 | #endif 86 | 87 | int sys_get_boot_cic(); 88 | void sys_set_boot_cic(int bc); 89 | volatile unsigned long get_ticks( void ); 90 | volatile unsigned long get_ticks_ms( void ); 91 | void wait_ticks( unsigned long wait ); 92 | void wait_ms( unsigned long wait ); 93 | 94 | void data_cache_hit_invalidate(volatile void *, unsigned long); 95 | void data_cache_hit_writeback(volatile void *, unsigned long); 96 | void data_cache_hit_writeback_invalidate(volatile void *, unsigned long); 97 | void data_cache_index_writeback_invalidate(volatile void *, unsigned long); 98 | void inst_cache_hit_writeback(volatile void *, unsigned long); 99 | void inst_cache_hit_invalidate(volatile void *, unsigned long); 100 | void inst_cache_index_invalidate(volatile void *, unsigned long); 101 | 102 | #ifdef __cplusplus 103 | } 104 | #endif 105 | 106 | /** 107 | * @brief Number of updates to the count register per second 108 | * 109 | * The count register updates at "half maximum instruction issue rate". 110 | * This appears to be half the CPU clock. Every second, this many counts 111 | * will have passed in the count register 112 | */ 113 | #define COUNTS_PER_SECOND (93750000/2) 114 | 115 | /** @} */ 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /files.in: -------------------------------------------------------------------------------- 1 | OFILES_LD = $(CURDIR)/build/n64sys.o 2 | OFILES_LD += $(CURDIR)/build/interrupt.o 3 | OFILES_LD += $(CURDIR)/build/inthandler.o 4 | OFILES_LD += $(CURDIR)/build/entrypoint.o 5 | OFILES_LD += $(CURDIR)/build/dragonfs.o 6 | OFILES_LD += $(CURDIR)/build/audio.o 7 | OFILES_LD += $(CURDIR)/build/display.o 8 | OFILES_LD += $(CURDIR)/build/console.o 9 | OFILES_LD += $(CURDIR)/build/controller.o 10 | OFILES_LD += $(CURDIR)/build/mempak.o 11 | OFILES_LD += $(CURDIR)/build/graphics.o 12 | OFILES_LD += $(CURDIR)/build/rdp.o 13 | OFILES_LD += $(CURDIR)/build/dma.o 14 | OFILES_LD += $(CURDIR)/build/timer.o 15 | OFILES_LD += $(CURDIR)/build/exception.o 16 | 17 | OFILES_LDS = $(CURDIR)/build/system.o 18 | 19 | OFILES_LDP = $(CURDIR)/build/n64sys.o 20 | OFILES_LDP += $(CURDIR)/build/interrupt.o 21 | OFILES_LDP += $(CURDIR)/build/inthandler.o 22 | OFILES_LDP += $(CURDIR)/build/entrypoint_2.o 23 | OFILES_LDP += $(CURDIR)/build/dragonfs.o 24 | OFILES_LDP += $(CURDIR)/build/audio.o 25 | OFILES_LDP += $(CURDIR)/build/display.o 26 | OFILES_LDP += $(CURDIR)/build/console.o 27 | OFILES_LDP += $(CURDIR)/build/controller.o 28 | OFILES_LDP += $(CURDIR)/build/graphics.o 29 | OFILES_LDP += $(CURDIR)/build/rdp.o 30 | OFILES_LDP += $(CURDIR)/build/dma.o 31 | OFILES_LDP += $(CURDIR)/build/timer.o 32 | OFILES_LDP += $(CURDIR)/build/exception.o 33 | OFILES_LDP += $(CURDIR)/build/do_ctors.o 34 | 35 | # Rules for compiling system stuff 36 | $(CURDIR)/build/n64sys.o: $(CURDIR)/src/n64sys.c 37 | mkdir -p $(CURDIR)/build 38 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/n64sys.o $(CURDIR)/src/n64sys.c 39 | $(CURDIR)/build/interrupt.o: $(CURDIR)/src/interrupt.c 40 | mkdir -p $(CURDIR)/build 41 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/interrupt.o $(CURDIR)/src/interrupt.c 42 | $(CURDIR)/build/dma.o: $(CURDIR)/src/dma.c 43 | mkdir -p $(CURDIR)/build 44 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/dma.o $(CURDIR)/src/dma.c 45 | $(CURDIR)/build/inthandler.o: $(CURDIR)/src/inthandler.S 46 | mkdir -p $(CURDIR)/build 47 | $(CC) -c -o $(CURDIR)/build/inthandler.o $(CURDIR)/src/inthandler.S 48 | $(CURDIR)/build/entrypoint.o: $(CURDIR)/src/entrypoint.S 49 | mkdir -p $(CURDIR)/build 50 | $(CC) -c -o $(CURDIR)/build/entrypoint.o $(CURDIR)/src/entrypoint.S 51 | 52 | # Rules for compiling filesystem 53 | $(CURDIR)/build/dragonfs.o: $(CURDIR)/src/dragonfs.c 54 | mkdir -p $(CURDIR)/build 55 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/dragonfs.o $(CURDIR)/src/dragonfs.c 56 | 57 | # Rules for compiling audio system 58 | $(CURDIR)/build/audio.o: $(CURDIR)/src/audio.c 59 | mkdir -p $(CURDIR)/build 60 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/audio.o $(CURDIR)/src/audio.c 61 | 62 | # Rules for compiling video system 63 | $(CURDIR)/build/display.o: $(CURDIR)/src/display.c 64 | mkdir -p $(CURDIR)/build 65 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/display.o $(CURDIR)/src/display.c 66 | $(CURDIR)/build/console.o: $(CURDIR)/src/console.c 67 | mkdir -p $(CURDIR)/build 68 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/console.o $(CURDIR)/src/console.c 69 | $(CURDIR)/build/graphics.o: $(CURDIR)/src/graphics.c 70 | mkdir -p $(CURDIR)/build 71 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/graphics.o $(CURDIR)/src/graphics.c 72 | $(CURDIR)/build/rdp.o: $(CURDIR)/src/rdp.c 73 | mkdir -p $(CURDIR)/build 74 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/rdp.o $(CURDIR)/src/rdp.c 75 | 76 | # Rules for compiling controller system 77 | $(CURDIR)/build/controller.o: $(CURDIR)/src/controller.c 78 | mkdir -p $(CURDIR)/build 79 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/controller.o $(CURDIR)/src/controller.c 80 | $(CURDIR)/build/mempak.o: $(CURDIR)/src/mempak.c 81 | mkdir -p $(CURDIR)/build 82 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/mempak.o $(CURDIR)/src/mempak.c 83 | 84 | # Rules for compiling timer system 85 | $(CURDIR)/build/timer.o: $(CURDIR)/src/timer.c 86 | mkdir -p $(CURDIR)/build 87 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/timer.o $(CURDIR)/src/timer.c 88 | 89 | # Rules for compiling exception system 90 | $(CURDIR)/build/exception.o: $(CURDIR)/src/exception.c 91 | mkdir -p $(CURDIR)/build 92 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/exception.o $(CURDIR)/src/exception.c 93 | 94 | # Rules for compiling newlib interface 95 | $(CURDIR)/build/system.o: $(CURDIR)/src/system.c 96 | mkdir -p $(CURDIR)/build 97 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/system.o $(CURDIR)/src/system.c 98 | 99 | # Rules for compiling c++ extras 100 | $(CURDIR)/build/entrypoint_2.o: $(CURDIR)/src/entrypoint_2.S 101 | mkdir -p $(CURDIR)/build 102 | $(CC) -c -o $(CURDIR)/build/entrypoint_2.o $(CURDIR)/src/entrypoint_2.S 103 | $(CURDIR)/build/do_ctors.o: $(CURDIR)/src/do_ctors.c 104 | mkdir -p $(CURDIR)/build 105 | $(CC) $(CFLAGS) -c -o $(CURDIR)/build/do_ctors.o $(CURDIR)/src/do_ctors.c 106 | -------------------------------------------------------------------------------- /include/controller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file controller.h 3 | * @brief Controller Subsystem 4 | * @ingroup controller 5 | */ 6 | #ifndef __LIBDRAGON_CONTROLLER_H 7 | #define __LIBDRAGON_CONTROLLER_H 8 | 9 | /** 10 | * @addtogroup controller 11 | * @{ 12 | */ 13 | 14 | /** 15 | * @name Bitmasks for controller status 16 | * @see #get_controllers_present 17 | * @see #get_accessories_present 18 | * @{ 19 | */ 20 | /** @brief Controller 1 Inserted */ 21 | #define CONTROLLER_1_INSERTED 0xF000 22 | /** @brief Controller 2 Inserted */ 23 | #define CONTROLLER_2_INSERTED 0x0F00 24 | /** @brief Controller 3 Inserted */ 25 | #define CONTROLLER_3_INSERTED 0x00F0 26 | /** @brief Controller 4 Inserted */ 27 | #define CONTROLLER_4_INSERTED 0x000F 28 | /** @} */ 29 | 30 | /** 31 | * @name Accessory ID Values 32 | * @see #identify_accessory 33 | * @{ 34 | */ 35 | /** @brief No accessory present */ 36 | #define ACCESSORY_NONE 0 37 | /** @brief Mempak present */ 38 | #define ACCESSORY_MEMPAK 1 39 | /** @brief Rumblepak present */ 40 | #define ACCESSORY_RUMBLEPAK 2 41 | /** @brief VRU present */ 42 | #define ACCESSORY_VRU 3 43 | /** @} */ 44 | 45 | /** 46 | * @name SI Error Values 47 | * @{ 48 | */ 49 | /** @brief No error occured */ 50 | #define ERROR_NONE 0x0 51 | /** @brief Command not recognized or malformed */ 52 | #define ERROR_BAD_COMMAND 0x1 53 | /** @brief Controller not present */ 54 | #define ERROR_NOT_PRESENT 0x2 55 | /** @} */ 56 | 57 | /** @brief SI Controller Data */ 58 | typedef struct SI_condat 59 | { 60 | /** @brief Unused padding bits */ 61 | unsigned : 16; 62 | /** @brief Status of the last command */ 63 | unsigned err : 2; 64 | /** @brief Unused padding bits */ 65 | unsigned : 14; 66 | 67 | union 68 | { 69 | struct 70 | { 71 | /** @brief 32-bit data sent to or returned from SI */ 72 | unsigned int data : 32; 73 | }; 74 | struct 75 | { 76 | /** @brief State of the A button */ 77 | unsigned A : 1; 78 | /** @brief State of the B button */ 79 | unsigned B : 1; 80 | /** @brief State of the Z button */ 81 | unsigned Z : 1; 82 | /** @brief State of the start button */ 83 | unsigned start : 1; 84 | /** @brief State of the up button */ 85 | unsigned up : 1; 86 | /** @brief State of the down button */ 87 | unsigned down : 1; 88 | /** @brief State of the left button */ 89 | unsigned left : 1; 90 | /** @brief State of the right button */ 91 | unsigned right : 1; 92 | /** @brief Unused padding bits */ 93 | unsigned : 2; 94 | /** @brief State of the L button */ 95 | unsigned L : 1; 96 | /** @brief State of the R button */ 97 | unsigned R : 1; 98 | /** @brief State of the C up button */ 99 | unsigned C_up : 1; 100 | /** @brief State of the C down button */ 101 | unsigned C_down : 1; 102 | /** @brief State of the C left button */ 103 | unsigned C_left : 1; 104 | /** @brief State of the C right button */ 105 | unsigned C_right : 1; 106 | /** @brief State of the X button */ 107 | signed x : 8; 108 | /** @brief State of the Y button */ 109 | signed y : 8; 110 | }; 111 | }; 112 | } _SI_condat; 113 | 114 | /** 115 | * @brief Structure for interpreting SI responses 116 | */ 117 | typedef struct controller_data 118 | { 119 | /** @brief Controller Data */ 120 | struct SI_condat c[4]; 121 | /** @brief Padding to allow mapping directly to a PIF block */ 122 | unsigned long unused[4*8]; 123 | } _controller_data; 124 | 125 | #ifdef __cplusplus 126 | extern "C" { 127 | #endif 128 | 129 | void controller_init(); 130 | void controller_read( struct controller_data * data); 131 | int get_controllers_present(); 132 | int get_accessories_present(); 133 | void controller_scan(); 134 | struct controller_data get_keys_down(); 135 | struct controller_data get_keys_up(); 136 | struct controller_data get_keys_held(); 137 | struct controller_data get_keys_pressed(); 138 | int get_dpad_direction( int controller ); 139 | int read_mempak_address( int controller, uint16_t address, uint8_t *data ); 140 | int write_mempak_address( int controller, uint16_t address, uint8_t *data ); 141 | int identify_accessory( int controller ); 142 | void rumble_start( int controller ); 143 | void rumble_stop( int controller ); 144 | void execute_raw_command( int controller, int command, int bytesout, int bytesin, unsigned char *out, unsigned char *in ); 145 | int eeprom_present(); 146 | void eeprom_read(int block, uint8_t * const buf); 147 | void eeprom_write(int block, const uint8_t * const data); 148 | 149 | #ifdef __cplusplus 150 | } 151 | #endif 152 | 153 | /** @} */ /* controller */ 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /src/dma.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dma.c 3 | * @brief DMA Controller 4 | * @ingroup dma 5 | */ 6 | #include "libdragon.h" 7 | #include "regsinternal.h" 8 | 9 | /** 10 | * @defgroup dma DMA Controller 11 | * @ingroup lowlevel 12 | * @brief DMA functionality for transfers between cartridge space and RDRAM 13 | * 14 | * The DMA controller is responsible for handling block and word accesses from 15 | * the catridge domain. Because of the nature of the catridge interface, code 16 | * cannot use memcpy or standard pointer accesses on memory mapped to the catridge. 17 | * Consequently, the peripheral interface (PI) provides a DMA controller for 18 | * accessing data. 19 | * 20 | * The DMA controller requires no initialization. Using #dma_read and #dma_write 21 | * will allow reading from the cartridge and writing to the catridge respectively 22 | * in block mode. #io_read and #io_write will allow a single 32-bit integer to 23 | * be read from or written to the cartridge. These are especially useful for 24 | * manipulating registers on a cartridge such as a gameshark. Code should never 25 | * make raw 32-bit reads or writes in the cartridge domain as it could collide with 26 | * an in-progress DMA transfer or run into caching issues. 27 | * @{ 28 | */ 29 | 30 | /** 31 | * @name PI Status Register Bit Definitions 32 | * @{ 33 | */ 34 | /** @brief PI DMA Busy */ 35 | #define PI_STATUS_DMA_BUSY ( 1 << 0 ) 36 | /** @brief PI IO Busy */ 37 | #define PI_STATUS_IO_BUSY ( 1 << 1 ) 38 | /** @brief PI Error */ 39 | #define PI_STATUS_ERROR ( 1 << 2 ) 40 | /** @} */ 41 | 42 | /** @brief Structure used to interact with the PI registers */ 43 | static volatile struct PI_regs_s * const PI_regs = (struct PI_regs_s *)0xa4600000; 44 | 45 | /** 46 | * @brief Return whether the DMA controller is currently busy 47 | * 48 | * @return nonzero if the DMA controller is busy or 0 otherwise 49 | */ 50 | volatile int dma_busy() 51 | { 52 | return PI_regs->status & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY); 53 | } 54 | 55 | /** 56 | * @brief Read from a peripheral 57 | * 58 | * This function should be used when reading from the cartridge. 59 | * 60 | * @param[out] ram_address 61 | * Pointer to a buffer to place read data 62 | * @param[in] pi_address 63 | * Memory address of the peripheral to read from 64 | * @param[in] len 65 | * Length in bytes to read into ram_address 66 | */ 67 | void dma_read(void * ram_address, unsigned long pi_address, unsigned long len) 68 | { 69 | disable_interrupts(); 70 | 71 | while (dma_busy()) ; 72 | MEMORY_BARRIER(); 73 | PI_regs->ram_address = ram_address; 74 | MEMORY_BARRIER(); 75 | PI_regs->pi_address = (pi_address | 0x10000000) & 0x1FFFFFFF; 76 | MEMORY_BARRIER(); 77 | PI_regs->write_length = len-1; 78 | MEMORY_BARRIER(); 79 | while (dma_busy()) ; 80 | 81 | enable_interrupts(); 82 | } 83 | 84 | /** 85 | * @brief Write to a peripheral 86 | * 87 | * This function should be used when writing to the cartridge. 88 | * 89 | * @param[in] ram_address 90 | * Pointer to a buffer to read data from 91 | * @param[in] pi_address 92 | * Memory address of the peripheral to write to 93 | * @param[in] len 94 | * Length in bytes to write to peripheral 95 | */ 96 | void dma_write(void * ram_address, unsigned long pi_address, unsigned long len) 97 | { 98 | disable_interrupts(); 99 | 100 | while (dma_busy()) ; 101 | MEMORY_BARRIER(); 102 | PI_regs->ram_address = ram_address; 103 | MEMORY_BARRIER(); 104 | PI_regs->pi_address = (pi_address | 0x10000000) & 0x1FFFFFFF; 105 | MEMORY_BARRIER(); 106 | PI_regs->read_length = len-1; 107 | MEMORY_BARRIER(); 108 | while (dma_busy()) ; 109 | 110 | enable_interrupts(); 111 | } 112 | 113 | /** 114 | * @brief Read a 32 bit integer from a peripheral 115 | * 116 | * @param[in] pi_address 117 | * Memory address of the peripheral to read from 118 | * 119 | * @return The 32 bit value read from the peripheral 120 | */ 121 | uint32_t io_read(uint32_t pi_address) 122 | { 123 | volatile uint32_t *uncached_address = (uint32_t *)(pi_address | 0xa0000000); 124 | uint32_t retval = 0; 125 | 126 | disable_interrupts(); 127 | 128 | /* Wait until there isn't a DMA transfer and grab a word */ 129 | while (dma_busy()) ; 130 | MEMORY_BARRIER(); 131 | retval = *uncached_address; 132 | MEMORY_BARRIER(); 133 | 134 | enable_interrupts(); 135 | 136 | return retval; 137 | } 138 | 139 | /** 140 | * @brief Write a 32 bit integer to a peripheral 141 | * 142 | * @param[in] pi_address 143 | * Memory address of the peripheral to write to 144 | * @param[in] data 145 | * 32 bit value to write to peripheral 146 | */ 147 | void io_write(uint32_t pi_address, uint32_t data) 148 | { 149 | volatile uint32_t *uncached_address = (uint32_t *)(pi_address | 0xa0000000); 150 | 151 | disable_interrupts(); 152 | 153 | while (dma_busy()) ; 154 | MEMORY_BARRIER(); 155 | *uncached_address = data; 156 | MEMORY_BARRIER(); 157 | 158 | enable_interrupts(); 159 | } 160 | 161 | /** @} */ /* dma */ 162 | -------------------------------------------------------------------------------- /include/regsinternal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file regsinternal.h 3 | * @brief Register definitions for various hardware in the N64 4 | * @ingroup lowlevel 5 | */ 6 | #ifndef __LIBDRAGON_REGSINTERNAL_H 7 | #define __LIBDRAGON_REGSINTERNAL_H 8 | 9 | /** 10 | * @defgroup lowlevel Low Level Hardware Interfaces 11 | * @ingroup libdragon 12 | * @brief Low level hardware interface descriptions and functionality 13 | * 14 | * The low level hardware interfaces handle several functions in the N64 that 15 | * would otherwise be handled by a kernel or RTOS. This includes the @ref dma, 16 | * the @ref exceptions, the @ref interrupt and the @ref n64sys. The DMA controller 17 | * handles DMA requests between the cartridge and the N64 RDRAM. Other systems 18 | * in the N64 have their own DMA controllers that are handled in the relevant 19 | * subsystems. The exception handler traps any exceptions raised by the N64, 20 | * including the reset exception. The interrupt handler sets up the MIPS 21 | * interface (MI) which handles low level interrupt functionality for all other 22 | * systems in the N64. The N64 system interface provides the ability for code to 23 | * manipulate cache and boot options. 24 | */ 25 | 26 | /** 27 | * @brief Register definition for the AI interface 28 | * @ingroup lowlevel 29 | */ 30 | typedef struct AI_regs_s { 31 | /** @brief Pointer to uncached memory buffer of samples to play */ 32 | volatile void * address; 33 | /** @brief Size in bytes of the buffer to be played. Should be 34 | * number of stereo samples * 2 * sizeof( uint16_t ) 35 | */ 36 | uint32_t length; 37 | /** @brief DMA start register. Write a 1 to this register to start 38 | * playing back an audio sample. */ 39 | uint32_t control; 40 | /** @brief AI status register. Bit 31 is the full bit, bit 30 is the busy bit. */ 41 | uint32_t status; 42 | /** @brief Rate at which the buffer should be played. 43 | * 44 | * Use the following formula to calculate the value: ((2 * clockrate / frequency) + 1) / 2 - 1 45 | */ 46 | uint32_t dacrate; 47 | /** @brief The size of a single sample in bits. */ 48 | uint32_t samplesize; 49 | } AI_regs_t; 50 | 51 | /** 52 | * @brief Register definition for the MI interface 53 | * @ingroup lowlevel 54 | */ 55 | typedef struct MI_regs_s { 56 | /** @brief Mode register */ 57 | uint32_t mode; 58 | /** @brief Version register */ 59 | uint32_t version; 60 | /** @brief Current interrupts on the system */ 61 | uint32_t intr; 62 | /** @brief Interrupt mask */ 63 | uint32_t mask; 64 | } MI_regs_t; 65 | 66 | /** 67 | * @brief Register definition for the VI interface 68 | * @ingroup lowlevel 69 | */ 70 | typedef struct VI_regs_s { 71 | /** @brief VI control register. Sets up various rasterization modes */ 72 | uint32_t control; 73 | /** @brief Pointer to uncached buffer in memory to rasterize */ 74 | void * framebuffer; 75 | /** @brief Width of the buffer in pixels */ 76 | uint32_t width; 77 | /** @brief Vertical interrupt control register. Controls which horizontal 78 | * line must be hit to generate a VI interrupt 79 | */ 80 | uint32_t v_int; 81 | /** @brief Current vertical line counter. */ 82 | uint32_t cur_line; 83 | /** @brief Timing generation register for PAL/NTSC signals */ 84 | uint32_t timing; 85 | /** @brief Number of lines per frame */ 86 | uint32_t v_sync; 87 | /** @brief Number of pixels in line and leap pattern */ 88 | uint32_t h_sync; 89 | /** @brief Number of pixels in line, set identically to h_sync */ 90 | uint32_t h_sync2; 91 | /** @brief Beginning and end of video horizontally */ 92 | uint32_t h_limits; 93 | /** @brief Beginning and end of video vertically */ 94 | uint32_t v_limits; 95 | /** @brief Beginning and end of color burst in vertical lines */ 96 | uint32_t color_burst; 97 | /** @brief Horizontal scaling factor from buffer to screen */ 98 | uint32_t h_scale; 99 | /** @brief Vertical scaling factor from buffer to screen */ 100 | uint32_t v_scale; 101 | } VI_regs_t; 102 | 103 | /** 104 | * @brief Register definition for the PI interface 105 | * @ingroup lowlevel 106 | */ 107 | typedef struct PI_regs_s { 108 | /** @brief Uncached address in RAM where data should be found */ 109 | volatile void * ram_address; 110 | /** @brief Address of data on peripheral */ 111 | uint32_t pi_address; 112 | /** @brief How much data to read from RAM into the peripheral */ 113 | uint32_t read_length; 114 | /** @brief How much data to write to RAM from the peripheral */ 115 | uint32_t write_length; 116 | /** @brief Status of the PI, including DMA busy */ 117 | uint32_t status; 118 | } PI_regs_t; 119 | 120 | /** 121 | * @brief Register definition for the SI interface 122 | * @ingroup lowlevel 123 | */ 124 | typedef struct SI_regs_s { 125 | /** @brief Uncached address in RAM where data should be found */ 126 | volatile void * DRAM_addr; 127 | /** @brief Address to read when copying from PIF RAM */ 128 | volatile void * PIF_addr_read; 129 | /** @brief Reserved word */ 130 | uint32_t reserved1; 131 | /** @brief Reserved word */ 132 | uint32_t reserved2; 133 | /** @brief Address to write when copying to PIF RAM */ 134 | volatile void * PIF_addr_write; 135 | /** @brief Reserved word */ 136 | uint32_t reserved3; 137 | /** @brief SI status, including DMA busy and IO busy */ 138 | uint32_t status; 139 | } SI_regs_t; 140 | 141 | /** 142 | * @brief Register definition for the SP interface 143 | * @ingroup lowlevel 144 | */ 145 | typedef struct SP_regs_s { 146 | /** @brief RSP memory address (IMEM/DMEM) */ 147 | volatile void * RSP_addr; 148 | /** @brief RDRAM memory address */ 149 | volatile void * RDAM_addr; 150 | /** @brief RDRAM->RSP DMA length */ 151 | uint32_t rsp_read_length; 152 | /** @brief RDP->RDRAM DMA length */ 153 | uint32_t rsp_write_length; 154 | /** @brief RSP status */ 155 | uint32_t status; 156 | /** @brief RSP DMA full */ 157 | uint32_t rsp_dma_full; 158 | /** @brief RSP DMA busy */ 159 | uint32_t rsp_dma_busy; 160 | /** @brief RSP Semaphore */ 161 | uint32_t rsp_semaphore; 162 | } SP_regs_t; 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /src/n64sys.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file n64sys.c 3 | * @brief N64 System Interface 4 | * @ingroup n64sys 5 | */ 6 | #include "n64sys.h" 7 | 8 | /** 9 | * @defgroup n64sys N64 System Interface 10 | * @ingroup lowlevel 11 | * @brief N64 bootup and cache interfaces. 12 | * 13 | * The N64 system interface provides a way for code to interact with 14 | * the memory setup on the system. This includes cache operations to 15 | * invalidate or flush regions and the ability to set the boot CIC. 16 | * The @ref system use the knowledge of the boot CIC to properly determine 17 | * if the expansion pak is present, giving 4MB of additional memory. Aside 18 | * from this, the MIPS r4300 uses a manual cache management strategy, where 19 | * SW that requires passing buffers to and from hardware components using 20 | * DMA controllers needs to ensure that cache and RDRAM are in sync. A 21 | * set of operations to invalidate and/or write back cache is provided for 22 | * both instruction cache and data cache. 23 | * @{ 24 | */ 25 | 26 | /** 27 | * @brief Boot CIC 28 | * 29 | * Defaults to 6102. 30 | */ 31 | int __bootcic = 6102; 32 | 33 | /** 34 | * @brief Return the boot CIC 35 | * 36 | * @return The boot CIC as an integer 37 | */ 38 | int sys_get_boot_cic() 39 | { 40 | return __bootcic; 41 | } 42 | 43 | /** 44 | * @brief Set the boot CIC 45 | * 46 | * This function will set the boot CIC. If the value isn't in the range 47 | * of 6102-6106, the boot CIC is set to the default of 6102. 48 | * 49 | * @param[in] bc 50 | * Boot CIC value 51 | */ 52 | void sys_set_boot_cic(int bc) 53 | { 54 | __bootcic = ( (bc >= 6102) && (bc <= 6106) ) ? bc : 6102; 55 | } 56 | 57 | /** 58 | * @brief Read the number of ticks since system startup 59 | * 60 | * @note This is the clock rate divided by two. 61 | * 62 | * @return The number of ticks since system startup 63 | */ 64 | volatile unsigned long get_ticks(void) 65 | { 66 | unsigned long count; 67 | // reg $9 on COP0 is count 68 | asm("\tmfc0 %0,$9\n\tnop":"=r"(count)); 69 | 70 | return count; 71 | } 72 | 73 | /** 74 | * @brief Read the number of millisecounds since system startup 75 | * 76 | * @return The number of millisecounds since system startup 77 | */ 78 | volatile unsigned long get_ticks_ms(void) 79 | { 80 | unsigned long count; 81 | // reg $9 on COP0 is count 82 | asm("\tmfc0 %0,$9\n\tnop":"=r"(count)); 83 | 84 | return count / (COUNTS_PER_SECOND / 1000); 85 | } 86 | 87 | /** 88 | * @brief Spin wait until the number of ticks have elapsed 89 | * 90 | * @param[in] wait 91 | * Number of ticks to wait 92 | */ 93 | void wait_ticks( unsigned long wait ) 94 | { 95 | unsigned int stop = wait + get_ticks(); 96 | 97 | while( stop > get_ticks() ); 98 | } 99 | 100 | /** 101 | * @brief Spin wait until the number of millisecounds have elapsed 102 | * 103 | * @param[in] wait 104 | * Number of millisecounds to wait 105 | */ 106 | void wait_ms( unsigned long wait ) 107 | { 108 | unsigned int stop = wait + get_ticks_ms(); 109 | 110 | while( stop > get_ticks_ms() ); 111 | } 112 | 113 | /** 114 | * @brief Helper macro to perform cache refresh operations 115 | * 116 | * @param[in] op 117 | * Operation to perform 118 | */ 119 | #define cache_op(op) \ 120 | addr=(void*)(((unsigned long)addr)&(~3));\ 121 | for (;length>0;length-=4,addr+=4) \ 122 | asm ("\tcache %0,(%1)\n"::"i" (op), "r" (addr)) 123 | 124 | /** 125 | * @brief Force a data cache writeback over a memory region 126 | * 127 | * Use this to force cached memory to be written to RDRAM. 128 | * 129 | * @param[in] addr 130 | * Pointer to memory in question 131 | * @param[in] length 132 | * Length in bytes of the data pointed at by addr 133 | */ 134 | void data_cache_hit_writeback(volatile void * addr, unsigned long length) 135 | { 136 | cache_op(0x19); 137 | } 138 | 139 | /** 140 | * @brief Force a data cache invalidate over a memory region 141 | * 142 | * Use this to force the N64 to update cache from RDRAM. 143 | * 144 | * @param[in] addr 145 | * Pointer to memory in question 146 | * @param[in] length 147 | * Length in bytes of the data pointed at by addr 148 | */ 149 | void data_cache_hit_invalidate(volatile void * addr, unsigned long length) 150 | { 151 | cache_op(0x11); 152 | } 153 | 154 | /** 155 | * @brief Force a data cache writeback invalidate over a memory region 156 | * 157 | * Use this to force cached memory to be written to RDRAM and then cache updated. 158 | * 159 | * @param[in] addr 160 | * Pointer to memory in question 161 | * @param[in] length 162 | * Length in bytes of the data pointed at by addr 163 | */ 164 | void data_cache_hit_writeback_invalidate(volatile void * addr, unsigned long length) 165 | { 166 | cache_op(0x15); 167 | } 168 | 169 | /** 170 | * @brief Force a data cache index writeback invalidate over a memory region 171 | * 172 | * @param[in] addr 173 | * Pointer to memory in question 174 | * @param[in] length 175 | * Length in bytes of the data pointed at by addr 176 | */ 177 | void data_cache_index_writeback_invalidate(volatile void * addr, unsigned long length) 178 | { 179 | cache_op(0x01); 180 | } 181 | 182 | /** 183 | * @brief Force an instruction cache writeback over a memory region 184 | * 185 | * Use this to force cached memory to be written to RDRAM. 186 | * 187 | * @param[in] addr 188 | * Pointer to memory in question 189 | * @param[in] length 190 | * Length in bytes of the data pointed at by addr 191 | */ 192 | void inst_cache_hit_writeback(volatile void * addr, unsigned long length) 193 | { 194 | cache_op(0x18); 195 | } 196 | 197 | /** 198 | * @brief Force an instruction cache invalidate over a memory region 199 | * 200 | * Use this to force the N64 to update cache from RDRAM. 201 | * 202 | * @param[in] addr 203 | * Pointer to memory in question 204 | * @param[in] length 205 | * Length in bytes of the data pointed at by addr 206 | */ 207 | void inst_cache_hit_invalidate(volatile void * addr, unsigned long length) 208 | { 209 | cache_op(0x10); 210 | } 211 | 212 | /** 213 | * @brief Force an instruction cache index invalidate over a memory region 214 | * 215 | * @param[in] addr 216 | * Pointer to memory in question 217 | * @param[in] length 218 | * Length in bytes of the data pointed at by addr 219 | */ 220 | void inst_cache_index_invalidate(volatile void * addr, unsigned long length) 221 | { 222 | cache_op(0x00); 223 | } 224 | 225 | /** @} */ 226 | -------------------------------------------------------------------------------- /src/inthandler.S: -------------------------------------------------------------------------------- 1 | /* 2 | Simple interrupt handler, hands off MIPS interrupts to higher level processes. 3 | Based on INITS.inc from Neon64. 4 | 5 | It is not reentrant, so interrupts are disabled for the duration. 6 | Safe for doing most things, including FPU operations, within handlers. 7 | */ 8 | 9 | #include "regs.S" 10 | 11 | inthandler: 12 | .global inthandler 13 | 14 | /*Save $2 before using*/ 15 | sd $2,save02 16 | 17 | .set noat 18 | /*Fetch exception pc off cop#0*/ 19 | mfc0 $2,C0_EPC 20 | nop 21 | 22 | la k1,save01 23 | sd $1,(k1) 24 | 25 | mfc0 k1,C0_SR 26 | la $1,saveSR 27 | sw k1,($1) 28 | la $1, ~1 29 | and k1,$1 30 | mtc0 k1,C0_SR 31 | .set at 32 | 33 | /*Save EPC now*/ 34 | sw $2,saveEPC 35 | 36 | /* save GPRs */ 37 | /*sd $2,save02 - removed , saved already.At this point it contains epc*/ 38 | sd $3,save03 39 | sd $4,save04 40 | sd $5,save05 41 | sd $6,save06 42 | sd $7,save07 43 | sd $8,save08 44 | sd $9,save09 45 | sd $10,save10 46 | sd $11,save11 47 | sd $12,save12 48 | sd $13,save13 49 | sd $14,save14 50 | sd $15,save15 51 | sd $16,save16 52 | sd $17,save17 53 | sd $18,save18 54 | sd $19,save19 55 | sd $20,save20 56 | sd $21,save21 57 | sd $22,save22 58 | sd $23,save23 59 | sd $24,save24 60 | sd $25,save25 61 | sd $26,save26 62 | sd $27,save27 63 | sd $28,save28 64 | sd $29,save29 65 | sd $30,save30 66 | sd $31,save31 67 | mflo $30 68 | sd $30,saveLO 69 | mfhi $30 70 | sd $30,saveHI 71 | cfc1 $30,$f31 72 | nop 73 | sd $30,saveFC31 74 | 75 | sdc1 $f0,saveFR00 76 | sdc1 $f1,saveFR01 77 | sdc1 $f2,saveFR02 78 | sdc1 $f3,saveFR03 79 | sdc1 $f4,saveFR04 80 | sdc1 $f5,saveFR05 81 | sdc1 $f6,saveFR06 82 | sdc1 $f7,saveFR07 83 | sdc1 $f8,saveFR08 84 | sdc1 $f9,saveFR09 85 | sdc1 $f10,saveFR10 86 | sdc1 $f11,saveFR11 87 | sdc1 $f12,saveFR12 88 | sdc1 $f13,saveFR13 89 | sdc1 $f14,saveFR14 90 | sdc1 $f15,saveFR15 91 | sdc1 $f16,saveFR16 92 | sdc1 $f17,saveFR17 93 | sdc1 $f18,saveFR18 94 | sdc1 $f19,saveFR19 95 | sdc1 $f20,saveFR20 96 | sdc1 $f21,saveFR21 97 | sdc1 $f22,saveFR22 98 | sdc1 $f23,saveFR23 99 | sdc1 $f24,saveFR24 100 | sdc1 $f25,saveFR25 101 | sdc1 $f26,saveFR26 102 | sdc1 $f27,saveFR27 103 | sdc1 $f28,saveFR28 104 | sdc1 $f29,saveFR29 105 | sdc1 $f30,saveFR30 106 | sdc1 $f31,saveFR31 107 | 108 | la sp,(exception_stack+65*1024-8) 109 | 110 | mfc0 k1,C0_CAUSE 111 | andi $30,k1,0xff 112 | beqz $30, justaninterrupt 113 | nop 114 | 115 | /*:(*/ 116 | jal __onCriticalException 117 | nop 118 | 119 | justaninterrupt: 120 | /* check for "pre-NMI" (reset) */ 121 | andi $30,k1,0x1000 122 | beqz $30, notprenmi 123 | nop 124 | 125 | /* handle reset */ 126 | jal __onResetException 127 | nop 128 | 129 | j endint 130 | nop 131 | notprenmi: 132 | 133 | /* check for count=compare */ 134 | and $30,k1,0x8000 135 | beqz $30,notcount 136 | nop 137 | mtc0 $0,$11 138 | 139 | /* handle timer exception */ 140 | jal __TI_handler 141 | nop 142 | 143 | j endint 144 | nop 145 | notcount: 146 | 147 | /* pass anything else along to handler */ 148 | jal __MI_handler 149 | nop 150 | 151 | endint: 152 | /* restore GPRs */ 153 | ld $2,save02 154 | ld $3,save03 155 | ld $4,save04 156 | ld $5,save05 157 | ld $6,save06 158 | ld $7,save07 159 | ld $8,save08 160 | ld $9,save09 161 | ld $10,save10 162 | ld $11,save11 163 | ld $12,save12 164 | ld $13,save13 165 | ld $14,save14 166 | ld $15,save15 167 | ld $16,save16 168 | ld $17,save17 169 | ld $18,save18 170 | ld $19,save19 171 | ld $20,save20 172 | ld $21,save21 173 | ld $22,save22 174 | ld $23,save23 175 | ld $24,save24 176 | ld $25,save25 177 | ld $26,save26 178 | ld $27,save27 179 | ld $28,save28 180 | ld $29,save29 181 | ld $31,save31 182 | lw $30,saveSR 183 | mtc0 $30,C0_SR 184 | ld $30,saveLO 185 | mtlo $30 186 | ld $30,saveHI 187 | mthi $30 188 | 189 | ldc1 $f0,saveFR00 190 | ldc1 $f1,saveFR01 191 | ldc1 $f2,saveFR02 192 | ldc1 $f3,saveFR03 193 | ldc1 $f4,saveFR04 194 | ldc1 $f5,saveFR05 195 | ldc1 $f6,saveFR06 196 | ldc1 $f7,saveFR07 197 | ldc1 $f8,saveFR08 198 | ldc1 $f9,saveFR09 199 | ldc1 $f10,saveFR10 200 | ldc1 $f11,saveFR11 201 | ldc1 $f12,saveFR12 202 | ldc1 $f13,saveFR13 203 | ldc1 $f14,saveFR14 204 | ldc1 $f15,saveFR15 205 | ldc1 $f16,saveFR16 206 | ldc1 $f17,saveFR17 207 | ldc1 $f18,saveFR18 208 | ldc1 $f19,saveFR19 209 | ldc1 $f20,saveFR20 210 | ldc1 $f21,saveFR21 211 | ldc1 $f22,saveFR22 212 | ldc1 $f23,saveFR23 213 | ldc1 $f24,saveFR24 214 | ldc1 $f25,saveFR25 215 | ldc1 $f26,saveFR26 216 | ldc1 $f27,saveFR27 217 | ldc1 $f28,saveFR28 218 | ldc1 $f29,saveFR29 219 | ldc1 $f30,saveFR30 220 | ldc1 $f31,saveFR31 221 | 222 | ld $30,saveFC31 223 | nop 224 | 225 | ctc1 $30,$f31 226 | 227 | ld $30,save30 228 | .set noat 229 | la $1,save01 230 | ld $1,($1) 231 | 232 | eret 233 | nop 234 | .set at 235 | 236 | .section .bss 237 | .global __baseRegAddr 238 | 239 | .align 8 240 | __baseRegAddr: 241 | .lcomm save01, 8 242 | .lcomm save02, 8 243 | .lcomm save03, 8 244 | .lcomm save04, 8 245 | .lcomm save05, 8 246 | .lcomm save06, 8 247 | .lcomm save07, 8 248 | .lcomm save08, 8 249 | .lcomm save09, 8 250 | .lcomm save10, 8 251 | .lcomm save11, 8 252 | .lcomm save12, 8 253 | .lcomm save13, 8 254 | .lcomm save14, 8 255 | .lcomm save15, 8 256 | .lcomm save16, 8 257 | .lcomm save17, 8 258 | .lcomm save18, 8 259 | .lcomm save19, 8 260 | .lcomm save20, 8 261 | .lcomm save21, 8 262 | .lcomm save22, 8 263 | .lcomm save23, 8 264 | .lcomm save24, 8 265 | .lcomm save25, 8 266 | .lcomm save26, 8 267 | .lcomm save27, 8 268 | .lcomm save28, 8 269 | .lcomm save29, 8 270 | .lcomm save30, 8 271 | .lcomm save31, 8 272 | .lcomm saveSR, 4 273 | .lcomm saveEPC, 4 274 | .lcomm saveHI, 8 275 | .lcomm saveLO, 8 276 | .lcomm saveFC31, 8 277 | .lcomm saveFR00, 8 278 | .lcomm saveFR01, 8 279 | .lcomm saveFR02, 8 280 | .lcomm saveFR03, 8 281 | .lcomm saveFR04, 8 282 | .lcomm saveFR05, 8 283 | .lcomm saveFR06, 8 284 | .lcomm saveFR07, 8 285 | .lcomm saveFR08, 8 286 | .lcomm saveFR09, 8 287 | .lcomm saveFR10, 8 288 | .lcomm saveFR11, 8 289 | .lcomm saveFR12, 8 290 | .lcomm saveFR13, 8 291 | .lcomm saveFR14, 8 292 | .lcomm saveFR15, 8 293 | .lcomm saveFR16, 8 294 | .lcomm saveFR17, 8 295 | .lcomm saveFR18, 8 296 | .lcomm saveFR19, 8 297 | .lcomm saveFR20, 8 298 | .lcomm saveFR21, 8 299 | .lcomm saveFR22, 8 300 | .lcomm saveFR23, 8 301 | .lcomm saveFR24, 8 302 | .lcomm saveFR25, 8 303 | .lcomm saveFR26, 8 304 | .lcomm saveFR27, 8 305 | .lcomm saveFR28, 8 306 | .lcomm saveFR29, 8 307 | .lcomm saveFR30, 8 308 | .lcomm saveFR31, 8 309 | .lcomm exception_stack, 65*1024 310 | 311 | -------------------------------------------------------------------------------- /src/regs.S: -------------------------------------------------------------------------------- 1 | /* 2 | * regs.S -- standard MIPS register names. 3 | * 4 | * Copyright (c) 1995 Cygnus Support 5 | * 6 | * The authors hereby grant permission to use, copy, modify, distribute, 7 | * and license this software and its documentation for any purpose, provided 8 | * that existing copyright notices are retained in all copies and that this 9 | * notice is included verbatim in any distributions. No written agreement, 10 | * license, or royalty fee is required for any of the authorized uses. 11 | * Modifications to this software may be copyrighted by their authors 12 | * and need not follow the licensing terms described here, provided that 13 | * the new terms are clearly indicated on the first page of each file where 14 | * they apply. 15 | */ 16 | 17 | /* Standard MIPS register names: */ 18 | #define zero $0 19 | #define z0 $0 20 | #define v0 $2 21 | #define v1 $3 22 | #define a0 $4 23 | #define a1 $5 24 | #define a2 $6 25 | #define a3 $7 26 | #define t0 $8 27 | #define t1 $9 28 | #define t2 $10 29 | #define t3 $11 30 | #define t4 $12 31 | #define t5 $13 32 | #define t6 $14 33 | #define t7 $15 34 | #define s0 $16 35 | #define s1 $17 36 | #define s2 $18 37 | #define s3 $19 38 | #define s4 $20 39 | #define s5 $21 40 | #define s6 $22 41 | #define s7 $23 42 | #define t8 $24 43 | #define t9 $25 44 | #define k0 $26 /* kernel private register 0 */ 45 | #define k1 $27 /* kernel private register 1 */ 46 | #define gp $28 /* global data pointer */ 47 | #define sp $29 /* stack-pointer */ 48 | #define fp $30 /* frame-pointer */ 49 | #define ra $31 /* return address */ 50 | #define pc $pc /* pc, used on mips16 */ 51 | 52 | #define fp0 $f0 53 | #define fp1 $f1 54 | 55 | /* Useful memory constants: */ 56 | #define K0BASE 0x80000000 57 | #ifndef __mips64 58 | #define K1BASE 0xA0000000 59 | #define K0BASE_ADDR ((char *)K0BASE) 60 | #define K1BASE_ADDR ((char *)K1BASE) 61 | #else 62 | #define K1BASE 0xFFFFFFFFA0000000LL 63 | #define K0BASE_ADDR ((char *)0xFFFFFFFF80000000LL) 64 | #define K1BASE_ADDR ((char *)K1BASE) 65 | #endif 66 | 67 | #define PHYS_TO_K1(a) ((unsigned)(a) | K1BASE) 68 | 69 | /* Standard Co-Processor 0 registers */ 70 | #define C0_COUNT $9 /* Timer Count Register */ 71 | #define C0_COMPARE $11 /* Timer Compare Register */ 72 | #define C0_SR $12 /* Status Register */ 73 | #define C0_CAUSE $13 /* last exception description */ 74 | #define C0_EPC $14 /* Exception error address */ 75 | #define C0_PRID $15 /* Processor Revision ID */ 76 | #define C0_CONFIG $16 /* CPU configuration */ 77 | 78 | /* Standard Processor Revision ID Register field offsets */ 79 | #define PR_IMP 8 80 | 81 | /* Standard Config Register field offsets */ 82 | #define CR_DB 4 83 | #define CR_IB 5 84 | #define CR_DC 6 /* NOTE v4121 semantics != 43,5xxx semantics */ 85 | #define CR_IC 9 /* NOTE v4121 semantics != 43,5xxx semantics */ 86 | #define CR_SC 17 87 | #define CR_SS 20 88 | #define CR_SB 22 89 | 90 | 91 | /* Standard Status Register bitmasks: */ 92 | #define SR_CU1 0x20000000 /* Mark CP1 as usable */ 93 | #define SR_FR 0x04000000 /* Enable MIPS III FP registers */ 94 | #define SR_BEV 0x00400000 /* Controls location of exception vectors */ 95 | #define SR_PE 0x00100000 /* Mark soft reset (clear parity error) */ 96 | 97 | #define SR_KX 0x00000080 /* Kernel extended addressing enabled */ 98 | #define SR_SX 0x00000040 /* Supervisor extended addressing enabled */ 99 | #define SR_UX 0x00000020 /* User extended addressing enabled */ 100 | 101 | /* Standard (R4000) cache operations. Taken from "MIPS R4000 102 | Microprocessor User's Manual" 2nd edition: */ 103 | 104 | #define CACHE_I (0) /* primary instruction */ 105 | #define CACHE_D (1) /* primary data */ 106 | #define CACHE_SI (2) /* secondary instruction */ 107 | #define CACHE_SD (3) /* secondary data (or combined instruction/data) */ 108 | 109 | #define INDEX_INVALIDATE (0) /* also encodes WRITEBACK if CACHE_D or CACHE_SD */ 110 | #define INDEX_LOAD_TAG (1) 111 | #define INDEX_STORE_TAG (2) 112 | #define CREATE_DIRTY_EXCLUSIVE (3) /* CACHE_D and CACHE_SD only */ 113 | #define HIT_INVALIDATE (4) 114 | #define CACHE_FILL (5) /* CACHE_I only */ 115 | #define HIT_WRITEBACK_INVALIDATE (5) /* CACHE_D and CACHE_SD only */ 116 | #define HIT_WRITEBACK (6) /* CACHE_I, CACHE_D and CACHE_SD only */ 117 | #define HIT_SET_VIRTUAL (7) /* CACHE_SI and CACHE_SD only */ 118 | 119 | #define BUILD_CACHE_OP(o,c) (((o) << 2) | (c)) 120 | 121 | /* Individual cache operations: */ 122 | #define INDEX_INVALIDATE_I BUILD_CACHE_OP(INDEX_INVALIDATE,CACHE_I) 123 | #define INDEX_WRITEBACK_INVALIDATE_D BUILD_CACHE_OP(INDEX_INVALIDATE,CACHE_D) 124 | #define INDEX_INVALIDATE_SI BUILD_CACHE_OP(INDEX_INVALIDATE,CACHE_SI) 125 | #define INDEX_WRITEBACK_INVALIDATE_SD BUILD_CACHE_OP(INDEX_INVALIDATE,CACHE_SD) 126 | 127 | #define INDEX_LOAD_TAG_I BUILD_CACHE_OP(INDEX_LOAD_TAG,CACHE_I) 128 | #define INDEX_LOAD_TAG_D BUILD_CACHE_OP(INDEX_LOAD_TAG,CACHE_D) 129 | #define INDEX_LOAD_TAG_SI BUILD_CACHE_OP(INDEX_LOAD_TAG,CACHE_SI) 130 | #define INDEX_LOAD_TAG_SD BUILD_CACHE_OP(INDEX_LOAD_TAG,CACHE_SD) 131 | 132 | #define INDEX_STORE_TAG_I BUILD_CACHE_OP(INDEX_STORE_TAG,CACHE_I) 133 | #define INDEX_STORE_TAG_D BUILD_CACHE_OP(INDEX_STORE_TAG,CACHE_D) 134 | #define INDEX_STORE_TAG_SI BUILD_CACHE_OP(INDEX_STORE_TAG,CACHE_SI) 135 | #define INDEX_STORE_TAG_SD BUILD_CACHE_OP(INDEX_STORE_TAG,CACHE_SD) 136 | 137 | #define CREATE_DIRTY_EXCLUSIVE_D BUILD_CACHE_OP(CREATE_DIRTY_EXCLUSIVE,CACHE_D) 138 | #define CREATE_DIRTY_EXCLUSIVE_SD BUILD_CACHE_OP(CREATE_DIRTY_EXCLUSIVE,CACHE_SD) 139 | 140 | #define HIT_INVALIDATE_I BUILD_CACHE_OP(HIT_INVALIDATE,CACHE_I) 141 | #define HIT_INVALIDATE_D BUILD_CACHE_OP(HIT_INVALIDATE,CACHE_D) 142 | #define HIT_INVALIDATE_SI BUILD_CACHE_OP(HIT_INVALIDATE,CACHE_SI) 143 | #define HIT_INVALIDATE_SD BUILD_CACHE_OP(HIT_INVALIDATE,CACHE_SD) 144 | 145 | #define CACHE_FILL_I BUILD_CACHE_OP(CACHE_FILL,CACHE_I) 146 | #define HIT_WRITEBACK_INVALIDATE_D BUILD_CACHE_OP(HIT_WRITEBACK_INVALIDATE,CACHE_D) 147 | #define HIT_WRITEBACK_INVALIDATE_SD BUILD_CACHE_OP(HIT_WRITEBACK_INVALIDATE,CACHE_SD) 148 | 149 | #define HIT_WRITEBACK_I BUILD_CACHE_OP(HIT_WRITEBACK,CACHE_I) 150 | #define HIT_WRITEBACK_D BUILD_CACHE_OP(HIT_WRITEBACK,CACHE_D) 151 | #define HIT_WRITEBACK_SD BUILD_CACHE_OP(HIT_WRITEBACK,CACHE_SD) 152 | 153 | #define HIT_SET_VIRTUAL_SI BUILD_CACHE_OP(HIT_SET_VIRTUAL,CACHE_SI) 154 | #define HIT_SET_VIRTUAL_SD BUILD_CACHE_OP(HIT_SET_VIRTUAL,CACHE_SD) 155 | 156 | /*> EOF regs.S <*/ 157 | -------------------------------------------------------------------------------- /include/system.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file system.h 3 | * @brief newlib Interface Hooks 4 | * @ingroup system 5 | */ 6 | #ifndef __LIBDRAGON_SYSTEM_H 7 | #define __LIBDRAGON_SYSTEM_H 8 | 9 | /** 10 | * @addtogroup system 11 | * @{ 12 | */ 13 | 14 | /** @brief Number of filesystems that can be attached to the system */ 15 | #define MAX_FILESYSTEMS 10 16 | /** @brief Number of open handles that can be maintained at one time */ 17 | #define MAX_OPEN_HANDLES 100 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | 25 | /** 26 | * @brief Filesystem hook structure 27 | * 28 | * Filesystems that do not support one of more of the following methods 29 | * should provide null pointers instead of empty functions. The newlib 30 | * hooks will set errno to ENOSYS and return a proper error to userspace. 31 | */ 32 | typedef struct 33 | { 34 | /** 35 | * @brief Function to call when performing an open command 36 | * 37 | * @param[in] name 38 | * Full path of the file to be opened, relative to the root 39 | * of the filesystem. 40 | * @param[in] flags 41 | * Open flags, such as binary, append, etc. Follows POSIX flags. 42 | * 43 | * @return A pointer to an arbitrary file handle assigned by the filesystem code 44 | * or NULL on error. 45 | */ 46 | void *(*open)( char *name, int flags ); 47 | /** 48 | * @brief Function to call when performing a fstat command 49 | * 50 | * @param[in] file 51 | * Arbitrary file handle returned by #filesystem_t::open 52 | * @param[out] st 53 | * Stat structure to populate with file statistics 54 | * 55 | * @return 0 on success or a negative value on error. 56 | */ 57 | int (*fstat)( void *file, struct stat *st ); 58 | /** 59 | * @brief Function to call when performing an lseek command 60 | * 61 | * @param[in] file 62 | * Arbitrary file handle returned by #filesystem_t::open 63 | * @param[in] ptr 64 | * An offset from dir to seek. 65 | * @param[in] dir 66 | * A direction to see, either SEEK_SET, SEEK_CUR or SEEK_END 67 | * 68 | * @return The absolute offset in bytes after the seek. 69 | */ 70 | int (*lseek)( void *file, int ptr, int dir ); 71 | /** 72 | * @brief Function to call when performing a read operation 73 | * 74 | * @param[in] file 75 | * Arbitrary file handle returned by #filesystem_t::open 76 | * @param[out] ptr 77 | * Buffer to place data read into 78 | * @param[in] len 79 | * Length of data that should be read into ptr 80 | * 81 | * @return The actual number of bytes read into ptr or a negative value on failure. 82 | */ 83 | int (*read)( void *file, uint8_t *ptr, int len ); 84 | /** @brief Function to call when performing a write operation 85 | * 86 | * @param[in] file 87 | * Arbitrary file handle returned by #filesystem_t::open 88 | * @param[out] ptr 89 | * Buffer to grab the data to be written 90 | * @param[in] len 91 | * Length of data that should be written out of ptr 92 | * 93 | * @return The actual number of bytes written or a negative value on failure. 94 | */ 95 | int (*write)( void *file, uint8_t *ptr, int len ); 96 | /** 97 | * @brief Function to call when performing a close operation 98 | * 99 | * @param[in] file 100 | * Arbitrary file handle returned by #filesystem_t::open 101 | * 102 | * @return 0 on success or a negative value on failure. 103 | */ 104 | int (*close)( void *file ); 105 | /** 106 | * @brief Function to call when performing an unlink operation 107 | * 108 | * @param[in] name 109 | * Full path of the file to be opened, relative to the root 110 | * of the filesystem. 111 | * 112 | * @return 0 on success or a negative value on failure. 113 | */ 114 | int (*unlink)( char *name ); 115 | /** 116 | * @brief Function to call when performing a findfirst operation 117 | * 118 | * @param[in] path 119 | * Full path of the directory to list files from, relative to the 120 | * root of the filesystem. 121 | * @param[out] dir 122 | * Directory structure to place information on the first file in the 123 | * directory. 124 | * 125 | * @return 0 on successful lookup or a negative value on failure or empty directory. 126 | */ 127 | int (*findfirst)( char *path, dir_t *dir ); 128 | /** 129 | * @brief Function to call when performing a findnext operation 130 | * 131 | * @param[out] dir 132 | * Directory structure to place information on the next file in the 133 | * directory. 134 | * 135 | * @return 0 on successful lookup or a negative value on failure or empty directory. 136 | */ 137 | int (*findnext)( dir_t *dir ); 138 | } filesystem_t; 139 | 140 | /** 141 | * @brief Standard I/O hook structure 142 | * 143 | * This structure provides optional callback hooks for code wishing to 144 | * respond to reads from STDIN or writes to STDOUT or STDERR. Any function 145 | * that code does not wish to handle should be left as a null pointer. 146 | */ 147 | typedef struct 148 | { 149 | /** 150 | * @brief Function to call when performing a STDIN read 151 | * 152 | * @param[out] data 153 | * Pointer to data buffer to place the read data 154 | * @param[in] len 155 | * Length of data in bytes expected to be read 156 | * 157 | * @return Actual number of bytes read into data, not to exceed the original length. 158 | */ 159 | int (*stdin_read)( char *data, unsigned int len ); 160 | /** 161 | * @brief Function to call when performing a STDOUT write 162 | * 163 | * @param[in] data 164 | * Pointer to data buffer containing the data to write 165 | * @param[in] len 166 | * Length of data in bytes expected to be written 167 | * 168 | * @return Actual number of bytes written from data, not to exceed the original length. 169 | */ 170 | int (*stdout_write)( char *data, unsigned int len ); 171 | /** 172 | * @brief Function to call when performing a STDERR write 173 | * 174 | * @param[in] data 175 | * Pointer to data buffer containing the data to write 176 | * @param[in] len 177 | * Length of data in bytes expected to be written 178 | * 179 | * @return Actual number of bytes written from data, not to exceed the original length. 180 | */ 181 | int (*stderr_write)( char *data, unsigned int len ); 182 | } stdio_t; 183 | 184 | int attach_filesystem( const char * const prefix, filesystem_t *filesystem ); 185 | int detach_filesystem( const char * const prefix ); 186 | 187 | int hook_stdio_calls( stdio_t *stdio_calls ); 188 | int unhook_stdio_calls(); 189 | 190 | #ifdef __cplusplus 191 | } 192 | #endif 193 | 194 | /** @} */ 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /tools/chksum64.c: -------------------------------------------------------------------------------- 1 | /* 2 | chksum64 V1.2, a program to calculate the ROM checksum of Nintendo64 ROMs. 3 | Copyright (C) 1997 Andreas Sterbenz (stan@sbox.tu-graz.ac.at) 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define max2(a, b) ( (a)>(b) ? (a) : (b) ) 25 | #define min2(a, b) ( (a)<(b) ? (a) : (b) ) 26 | 27 | #define BUFSIZE 32768 28 | 29 | #define CHECKSUM_START 0x1000 30 | #define CHECKSUM_LENGTH 0x100000L 31 | #define CHECKSUM_HEADERPOS 0x10 32 | #define CHECKSUM_END (CHECKSUM_START + CHECKSUM_LENGTH) 33 | 34 | #define CHECKSUM_STARTVALUE 0xf8ca4ddc 35 | 36 | #define ROL(i, b) (((i)<<(b)) | ((i)>>(32-(b)))) 37 | 38 | #define BYTES2LONG(b, s) ( (((b)[0^(s)] & 0xffL) << 24) | \ 39 | (((b)[1^(s)] & 0xffL) << 16) | \ 40 | (((b)[2^(s)] & 0xffL) << 8) | \ 41 | (((b)[3^(s)] & 0xffL)) ) 42 | 43 | #define LONG2BYTES(l, b, s) (b)[0^(s)] = ((l)>>24)&0xff; \ 44 | (b)[1^(s)] = ((l)>>16)&0xff; \ 45 | (b)[2^(s)] = ((l)>> 8)&0xff; \ 46 | (b)[3^(s)] = ((l) )&0xff; 47 | 48 | #define HEADER_MAGIC 0x80371240 49 | 50 | void usage(char *progname) 51 | { 52 | fprintf(stderr, "Usage: %s [-r] [-o|-s] \n\n", progname); 53 | fprintf(stderr, "This program calculates the ROM checksum for Nintendo64 ROM images.\n"); 54 | fprintf(stderr, "Checksum code reverse engineered from Nagra's program.\n"); 55 | exit(2); 56 | } 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | FILE *file1; 61 | char *fname1=NULL, *progname=argv[0]; 62 | unsigned char buffer1[BUFSIZE]; 63 | unsigned int flen1; 64 | unsigned int sum1, sum2; 65 | int swapped=-1; 66 | int readonly = 0; 67 | 68 | printf("CHKSUM64 V1.2 Copyright (C) 1997 Andreas Sterbenz (stan@sbox.tu-graz.ac.at)\n"); 69 | printf("This program is released under the terms of the GNU public license. NO WARRANTY\n\n"); 70 | 71 | { 72 | int i; 73 | 74 | for( i=1; i 0 ) { 180 | n = fread(buffer1, 1, min2(BUFSIZE, clen), file1); 181 | if( (n & 0x03) != 0 ) { 182 | n += fread(buffer1+n, 1, 4-(n&3), file1); 183 | } 184 | } else { 185 | n = min2(BUFSIZE, clen); 186 | } 187 | if( (n == 0) || ((n&3) != 0) ) { 188 | if( (clen != 0) || (n != 0) ) { 189 | fprintf(stderr, "WARNING: Short read, checksum may be incorrect.\n"); 190 | } 191 | break; 192 | } 193 | for( i=0; i 0 ) { 210 | rlen -= n; 211 | if( rlen <= 0 ) memset(buffer1, 0, BUFSIZE); 212 | } 213 | clen -= n; 214 | } 215 | sum1 = t6 ^ t4 ^ t3; 216 | sum2 = t5 ^ t2 ^ t1; 217 | } 218 | LONG2BYTES(sum1, &buffer1[0], 0); 219 | LONG2BYTES(sum2, &buffer1[4], 0); 220 | fseek(file1, CHECKSUM_HEADERPOS, SEEK_SET); 221 | fread(buffer1+8, 1, 8, file1); 222 | printf("Old Checksum: "); 223 | printf("%02X %02X %02X %02X ", buffer1[ 8^swapped], buffer1[ 9^swapped], buffer1[10^swapped], buffer1[11^swapped]); 224 | printf("%02X %02X %02X %02X\n", buffer1[12^swapped], buffer1[13^swapped], buffer1[14^swapped], buffer1[15^swapped]); 225 | printf("Calculated Checksum: "); 226 | printf("%02X %02X %02X %02X ", buffer1[0], buffer1[1], buffer1[2], buffer1[3]); 227 | printf("%02X %02X %02X %02X\n", buffer1[4], buffer1[5], buffer1[6], buffer1[7]); 228 | if( readonly == 0 ) { 229 | fseek(file1, CHECKSUM_HEADERPOS, SEEK_SET); 230 | LONG2BYTES(sum1, &buffer1[16], swapped); 231 | LONG2BYTES(sum2, &buffer1[20], swapped); 232 | if( fwrite(buffer1+16, 1, 8, file1) != 8 ) { 233 | fprintf(stderr, "%s: Could not write new checksum to file '%s'!\n", progname, fname1); 234 | exit(1); 235 | } else { 236 | printf("New checksum successfully written.\n"); 237 | } 238 | } else { 239 | printf("File opened in read-only mode, new checksum not written.\n"); 240 | } 241 | fclose(file1); 242 | return 0; 243 | } 244 | -------------------------------------------------------------------------------- /tools/mksprite/mksprite.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define BITDEPTH_16BPP 16 11 | #define BITDEPTH_32BPP 32 12 | 13 | #define FORMAT_UNCOMPRESSED 0 14 | 15 | #if BYTE_ORDER == BIG_ENDIAN 16 | #define SWAP_WORD(x) (x) 17 | #else 18 | #define SWAP_WORD(x) ((((x)>>8) & 0x00FF) | (((x)<<8) & 0xFF00)) 19 | #endif 20 | 21 | void write_value( uint8_t *colorbuf, FILE *fp, int bitdepth ) 22 | { 23 | if( bitdepth == BITDEPTH_16BPP ) 24 | { 25 | uint16_t out = SWAP_WORD((((colorbuf[0] >> 3) & 0x1F) << 11) | (((colorbuf[1] >> 3) & 0x1F) << 6) | 26 | (((colorbuf[2] >> 3) & 0x1F) << 1) | (colorbuf[3] >> 7)); 27 | 28 | fwrite( &out, 1, 2, fp ); 29 | } 30 | else 31 | { 32 | /* Just write out */ 33 | fwrite( colorbuf, 1, 4, fp ); 34 | } 35 | } 36 | 37 | int read_png( char *png_file, char *spr_file, int depth, int hslices, int vslices ) 38 | { 39 | png_structp png_ptr; 40 | png_infop info_ptr; 41 | png_uint_32 width, height; 42 | int bit_depth, color_type, interlace_type; 43 | uint8_t wval8; 44 | uint16_t wval16; 45 | FILE *fp; 46 | FILE *op; 47 | int err = 0; 48 | 49 | /* Open file descriptors for read and write */ 50 | if ((fp = fopen(png_file, "rb")) == NULL) 51 | { 52 | return -ENOENT; 53 | } 54 | 55 | if ((op = fopen(spr_file, "wb")) == NULL) 56 | { 57 | fclose(fp); 58 | 59 | return -ENOENT; 60 | } 61 | 62 | /* Allocate/initialize the memory for the PNG library. */ 63 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 64 | 65 | if (png_ptr == NULL) 66 | { 67 | fclose(fp); 68 | fclose(op); 69 | 70 | err = -ENOMEM; 71 | goto exitfiles; 72 | } 73 | 74 | /* Allocate/initialize the memory for image information. */ 75 | info_ptr = png_create_info_struct( png_ptr ); 76 | if (info_ptr == NULL) 77 | { 78 | err = -ENOMEM; 79 | goto exitpng; 80 | } 81 | 82 | /* Error handler to gracefully exit */ 83 | if (setjmp(png_jmpbuf(png_ptr))) 84 | { 85 | /* Free all of the memory associated with the png_ptr and info_ptr */ 86 | err = -EINTR; 87 | goto exitpng; 88 | } 89 | 90 | /* Tie input to file opened earlier */ 91 | png_init_io(png_ptr, fp); 92 | 93 | /* Read PNG header to populate below entries */ 94 | png_read_info(png_ptr, info_ptr); 95 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); 96 | 97 | /* Write sprite header widht and height */ 98 | wval16 = SWAP_WORD((uint16_t)width); 99 | fwrite( &wval16, sizeof( wval16 ), 1, op ); 100 | wval16 = SWAP_WORD((uint16_t)height); 101 | fwrite( &wval16, sizeof( wval16 ), 1, op ); 102 | 103 | /* Bitdepth */ 104 | wval8 = (depth == BITDEPTH_32BPP) ? 4 : 2; 105 | fwrite( &wval8, sizeof( wval8 ), 1, op ); 106 | 107 | /* Format */ 108 | wval8 = FORMAT_UNCOMPRESSED; 109 | fwrite( &wval8, sizeof( wval8 ), 1, op ); 110 | 111 | /* Horizontal and vertical slices */ 112 | wval8 = hslices; 113 | fwrite( &wval8, sizeof( wval8 ), 1, op ); 114 | wval8 = vslices; 115 | fwrite( &wval8, sizeof( wval8 ), 1, op ); 116 | 117 | /* Change pallete to RGB */ 118 | if(color_type == PNG_COLOR_TYPE_PALETTE) 119 | png_set_palette_to_rgb(png_ptr); 120 | 121 | /* Change bit-packed grayscale images to 8bit */ 122 | if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 123 | png_set_expand_gray_1_2_4_to_8(png_ptr); 124 | 125 | /* Go from 16 to 8 bits per channel */ 126 | if(bit_depth == 16) 127 | png_set_strip_16(png_ptr); 128 | 129 | /* Change transparency to alpha value */ 130 | if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) 131 | png_set_tRNS_to_alpha(png_ptr); 132 | 133 | /* Convert single channel grayscale to RGB */ 134 | if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 135 | png_set_gray_to_rgb(png_ptr); 136 | /* Ensure interlacing works and then update the color info since we changed things */ 137 | png_set_interlace_handling(png_ptr); 138 | png_read_update_info(png_ptr, info_ptr); 139 | 140 | /* Update the color type from the above re-read */ 141 | color_type = png_get_color_type(png_ptr, info_ptr); 142 | bit_depth = png_get_bit_depth(png_ptr, info_ptr); 143 | 144 | /* Keep the variably sized array scoped so we can goto past it */ 145 | { 146 | /* The easiest way to read the image (all at once) */ 147 | png_bytep row_pointers[height]; 148 | memset( row_pointers, 0, sizeof( png_bytep ) * height ); 149 | 150 | for( int row = 0; row < height; row++ ) 151 | { 152 | row_pointers[row] = malloc(png_get_rowbytes(png_ptr, info_ptr)); 153 | 154 | if( row_pointers[row] == NULL ) 155 | { 156 | fprintf(stderr, "Unable to allocate space for row pointers!\n"); 157 | 158 | err = -ENOMEM; 159 | goto exitmem; 160 | } 161 | } 162 | 163 | /* Now it's time to read the image. */ 164 | png_read_image(png_ptr, row_pointers); 165 | 166 | /* Translate out to sprite format */ 167 | switch( color_type ) 168 | { 169 | case PNG_COLOR_TYPE_RGB: 170 | /* No alpha channel, must set to default full opaque */ 171 | fprintf(stderr, "No alpha channel, substituting full opaque!\n"); 172 | 173 | for( int j = 0; j < height; j++) 174 | { 175 | for( int i = 0; i < width; i++ ) 176 | { 177 | uint8_t buf[4]; 178 | 179 | buf[0] = row_pointers[j][(i * 3)]; 180 | buf[1] = row_pointers[j][(i * 3) + 1]; 181 | buf[2] = row_pointers[j][(i * 3) + 2]; 182 | buf[3] = 255; 183 | 184 | write_value( buf, op, depth ); 185 | } 186 | } 187 | 188 | break; 189 | case PNG_COLOR_TYPE_RGB_ALPHA: 190 | /* Easy, just dump rows or convert */ 191 | for( int row = 0; row < height; row++ ) 192 | { 193 | for( int col = 0; col < width; col++ ) 194 | { 195 | write_value( &row_pointers[row][col * 4], op, depth ); 196 | } 197 | } 198 | 199 | break; 200 | } 201 | 202 | exitmem: 203 | /* Free the row pointers memory */ 204 | for( int row = 0; row < height; row++ ) 205 | { 206 | if( row_pointers[row] ) 207 | { 208 | free( row_pointers[row] ); 209 | row_pointers[row] = 0; 210 | } 211 | } 212 | } 213 | 214 | exitpng: 215 | /* Clean up after the read, and free any memory allocated */ 216 | png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 217 | 218 | exitfiles: 219 | /* Close the files */ 220 | fclose(fp); 221 | fclose(op); 222 | 223 | return err; 224 | } 225 | 226 | void print_args( char * name ) 227 | { 228 | fprintf( stderr, "Usage: %s [ ] \n", name ); 229 | fprintf( stderr, "\t should be 16 or 32.\n" ); 230 | fprintf( stderr, "\t should be a number two or greater signifying how many images are in this spritemap horizontally.\n" ); 231 | fprintf( stderr, "\t should be a number two or greater signifying how many images are in this spritemap vertically.\n" ); 232 | fprintf( stderr, "\t should be any valid PNG file.\n" ); 233 | fprintf( stderr, "\t will be written in binary for inclusion using DragonFS.\n" ); 234 | } 235 | 236 | int main( int argc, char *argv[] ) 237 | { 238 | int bitdepth; 239 | 240 | if( argc != 4 && argc != 6 ) 241 | { 242 | print_args( argv[0] ); 243 | return -EINVAL; 244 | } 245 | 246 | /* Covert bitdepth argument */ 247 | bitdepth = atoi( argv[1] ); 248 | 249 | if( bitdepth == 32 ) 250 | { 251 | bitdepth = BITDEPTH_32BPP; 252 | } 253 | else if( bitdepth == 16 ) 254 | { 255 | bitdepth = BITDEPTH_16BPP; 256 | } 257 | else 258 | { 259 | print_args( argv[0] ); 260 | return -EINVAL; 261 | } 262 | 263 | if( argc == 4 ) 264 | { 265 | /* Translate, return result */ 266 | return read_png( argv[2], argv[3], bitdepth, 1, 1 ); 267 | } 268 | else 269 | { 270 | int hslices = atoi( argv[2] ); 271 | int vslices = atoi( argv[3] ); 272 | 273 | /* Translate, return result */ 274 | return read_png( argv[4], argv[5], bitdepth, hslices, vslices ); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /examples/fire/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "system.c" 10 | #include "controls.c" 11 | 12 | // SYSTEM 13 | static sprite_t *graph[50]; // sprites (0..40 background, 41..45 fire, 46 stick, 47 light) 14 | static display_context_t disp = 0; // screen 15 | char tStr[32]; // text 16 | 17 | // INTERNAL FUNCTIONS 18 | int error=-1; 19 | 20 | // FPS 21 | int16_t fps_tick=0; 22 | int16_t fps_sec=0; 23 | 24 | // TEST VARIABLES 25 | int mouse_x=160; 26 | int mouse_y=120; 27 | int num; 28 | 29 | // FRAMEBUFFER 30 | uint16_t buffer_texture[768]={0}; // 24*32 31 | int buffer_width=24; 32 | int buffer_height=32; 33 | int buffer_x=0; 34 | int angle=0; 35 | int radius=4; 36 | int waves=25000; 37 | int speed=4000; 38 | int delay=0; 39 | 40 | // FIRE 41 | typedef struct 42 | { 43 | int x; 44 | int y; 45 | int alpha; 46 | } fire; 47 | 48 | fire fire_obj[100]; 49 | 50 | int max_fire=0; 51 | int sel_fire=0; 52 | int fire_anim=0; 53 | int fire_tick=0; 54 | float sphere_size=1.0; 55 | 56 | // PROGRAM 57 | int main(void) 58 | { 59 | // INTERRUPTS 60 | init_interrupts(); 61 | 62 | // VIDEO 63 | display_init( RESOLUTION_320x240, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE ); 64 | 65 | // SYSTEM INIT 66 | dfs_init(DFS_DEFAULT_LOCATION); 67 | rdp_init(); 68 | controller_init(); 69 | timer_init(); 70 | 71 | // FPS 72 | new_timer(TIMER_TICKS(1000000), TF_CONTINUOUS, update_counter); 73 | 74 | // INIT RAND 75 | srand(timer_ticks() & 0x7FFFFFFF); 76 | 77 | int i=0; 78 | int i1=0; 79 | char sprite_path[32]; 80 | 81 | // BASIC RDP CONFIG 82 | uint64_t RDP_CONFIG = ATOMIC_PRIM | ALPHA_DITHER_SEL_NO_DITHER | RGB_DITHER_SEL_NO_DITHER; // VERY IMPORTANT, this example needs atomic prim or crashes in real hardware 83 | 84 | // LOAD SPRITES 85 | for(i=1;i<48;i++) 86 | { 87 | sprintf(sprite_path,"/%d.sprite",i); 88 | graph[i] = load_sprite(sprite_path); 89 | 90 | if (graph[i]==0) 91 | { 92 | error=i+1; 93 | break; 94 | } 95 | } 96 | 97 | // LOOP 98 | while(1) 99 | { 100 | // WAIT BUFFER 101 | while( !(disp = display_lock()) ); 102 | 103 | // SET CLIPPING (we don't clear buffer, the background covers the full screen) 104 | rdp_attach_display(disp); 105 | rdp_sync(SYNC_PIPE); 106 | rdp_set_clipping(0,0,320,240); 107 | 108 | // SCAN CONTROLS 109 | update_controls(); 110 | 111 | // RDP COPY MODE 112 | rdp_texture_copy(RDP_CONFIG); 113 | 114 | // DRAW BACKGROUND 115 | num=1; 116 | for(i=0;i<240;i+=32) // Y 117 | { 118 | for(i1=0;i1<320;i1+=64) // X 119 | { 120 | rdp_load_texture(graph[num]); 121 | rdp_draw_sprite(i1,i,0); 122 | num++; 123 | } 124 | } 125 | 126 | // JOYSTICK CONTROL 127 | if (joystick_x<-4 || joystick_x>4) { mouse_x+=joystick_x/5; } 128 | if (joystick_y<-4 || joystick_y>4) { mouse_y-=joystick_y/5; } 129 | 130 | if (mouse_x<32) { mouse_x=32; } 131 | if (mouse_x>288) { mouse_x=288; } 132 | if (mouse_y<48) { mouse_y=48; } 133 | if (mouse_y>208) { mouse_y=208; } 134 | 135 | // FRAMEBUFFER S DEFORMATION 136 | rdp_buffer_copy(disp,buffer_texture,mouse_x-12,mouse_y-40,buffer_width,buffer_height,1); // do texture from framebuffer, but don't load on TMEM yet 137 | 138 | angle=delay; 139 | 140 | for(i=0;i7) 161 | buffer_x=7; 162 | 163 | buffer_x=buffer_x-4; 164 | 165 | if (i0) 197 | { 198 | sel_fire++; 199 | 200 | if (max_fire<99) // 99 sprites max 201 | max_fire++; 202 | 203 | if (sel_fire>99) // Fire variables will be recycled 204 | sel_fire=1; 205 | 206 | fire_obj[sel_fire].x=mouse_x+randx(-2,2); 207 | fire_obj[sel_fire].y=mouse_y+randx(-2,2); 208 | fire_obj[sel_fire].alpha=129; 209 | 210 | if (z_button>0) // Z does blur effect 211 | fire_obj[sel_fire].alpha=128; 212 | } 213 | 214 | // START BUTTON RESETS FIRE 215 | if (start_button==1) 216 | { 217 | max_fire=0; 218 | sel_fire=0; 219 | } 220 | 221 | // FIRE (without reload TMEM) 222 | if (max_fire>0) 223 | { 224 | for(i=1;i8) // only if visible 227 | { 228 | if (fire_obj[i].alpha<129) // fire will vanish (Z button) 229 | { 230 | fire_obj[i].alpha-=8; 231 | rdp_set_prim_color(255,255,255,fire_obj[i].alpha); 232 | } 233 | else 234 | rdp_set_prim_color(255,255,255,128); // fire stays on screen (A button) 235 | 236 | // DRAW 237 | rdp_cp_sprite(fire_obj[i].x,fire_obj[i].y,0,0,0,0); 238 | } 239 | } 240 | } 241 | 242 | // ANIMATION TIED TO FRAMERATE 243 | if (fire_tick==0) 244 | { 245 | fire_tick=4; // delay 246 | fire_anim++; 247 | if (fire_anim>4) 248 | fire_anim=0; 249 | } 250 | else 251 | fire_tick--; 252 | 253 | // DRAW CIRCLE LIGHT 254 | rdp_set_prim_color(255,255,255,randx(16,48)); // alpha is random between 16 and 48 255 | rdp_texture_cycle(0,1,RDP_CONFIG | SAMPLE_TYPE); // light is smoother with filter (1cycle,alpha,config+filter enabled) 256 | rdp_load_texture(graph[47]); 257 | sphere_size=(randx(70,100)/100.0)+1.0; // the size of the lighting is variable too 258 | rdp_cp_sprite_scaled(mouse_x,mouse_y-16,sphere_size,sphere_size,0,16,16,0); // CP sprite with input center x16 y16 (which is the center of the 32x32 sphere) 259 | 260 | // RDP IS DONE 261 | rdp_detach_display(); 262 | 263 | // FRAMERATE 264 | if(framerate_refresh==1) 265 | { 266 | fps_sec=fps_tick; 267 | fps_tick=0; 268 | framerate_refresh=0; 269 | } 270 | fps_tick++; 271 | 272 | // TEXT 273 | sprintf(tStr,"FPS: %d\n",fps_sec); 274 | graphics_draw_text(disp,40,10,tStr); 275 | 276 | if (error>0) 277 | { 278 | sprintf(tStr,"FILE: %d\n",error-1); 279 | graphics_draw_text(disp,40,200,tStr); 280 | } 281 | 282 | // FRAME READY 283 | display_show(disp); 284 | } 285 | } -------------------------------------------------------------------------------- /src/console.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file console.c 3 | * @brief Console Support 4 | * @ingroup console 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "system.h" 14 | #include "libdragon.h" 15 | 16 | /** 17 | * @defgroup console Console Support 18 | * @ingroup display 19 | * @brief Software console emulation for debugging and simple text output. 20 | * 21 | * Console support is provided as a poor-man's console for simple debugging on 22 | * the N64. It does not respect common escape sequences and is nonstandard in 23 | * size. When using the console, code should be careful to make sure that the 24 | * display system has not been initialized. Similarly, if the display system 25 | * is needed, code should be sure that the console is not initialized. 26 | * 27 | * Code wishing to use the console should first initialize the console support in 28 | * libdragon with #console_init. Once the console has been initialized, it wil 29 | * operate in one of two modes. In automatic mode, every write to the console will 30 | * be immediately displayed on the screen. The console will be scrolled when the 31 | * buffer fills. In manual mode, the console will only be displayed after calling 32 | * #console_render. To set the render mode, use #console_set_render_mode. To 33 | * add data to the console, use #printf or #iprintf. To clear the console and reset 34 | * the scroll, use #console_clear. Once the console is not needed or when the 35 | * code wishes to switch to the display subsystem, #console_clear should be called 36 | * to cleanly shut down the console support. 37 | * 38 | * @{ 39 | */ 40 | 41 | /* Prototypes */ 42 | static void __console_render(); 43 | 44 | /** @brief Size of the console buffer in bytes */ 45 | #define CONSOLE_SIZE ((sizeof(char) * CONSOLE_WIDTH * CONSOLE_HEIGHT) + sizeof(char)) 46 | 47 | /** @brief The console buffer */ 48 | static char *render_buffer = 0; 49 | /** 50 | * @brief Internal state of the render mode 51 | * @see #RENDER_AUTOMATIC and #RENDER_MANUAL 52 | */ 53 | static int render_now; 54 | 55 | /** 56 | * @brief Set the console rendering mode 57 | * 58 | * This sets the render mode of the console. The #RENDER_AUTOMATIC mode allows 59 | * console_printf to immediately be placed onto the screen. This is very similar 60 | * to a normal console on a unix/windows system. The #RENDER_MANUAL mode allows 61 | * console_printf to be buffered, and displayed at a later date using 62 | * console_render(). This is to allow a rendering interface somewhat analogous 63 | * to curses 64 | * 65 | * @param[in] mode 66 | * Render mode (#RENDER_AUTOMATIC or #RENDER_MANUAL) 67 | */ 68 | void console_set_render_mode(int mode) 69 | { 70 | /* Allow manual buffering somewhat like curses */ 71 | render_now = mode; 72 | } 73 | 74 | /** 75 | * @brief Macro to move the console up one line 76 | */ 77 | #define move_buffer() \ 78 | memmove(render_buffer, render_buffer + (sizeof(char) * CONSOLE_WIDTH), CONSOLE_SIZE - (CONSOLE_WIDTH * sizeof(char))); \ 79 | pos -= CONSOLE_WIDTH; 80 | 81 | /** 82 | * @brief Newlib hook to allow printf/iprintf to appear on console 83 | * 84 | * @param[in] buf 85 | * Pointer to data buffer containing the data to write 86 | * @param[in] len 87 | * Length of data in bytes expected to be written 88 | * 89 | * @return Number of bytes written 90 | */ 91 | static int __console_write( char *buf, unsigned int len ) 92 | { 93 | int pos = strlen(render_buffer); 94 | 95 | /* Copy over to screen buffer */ 96 | for(int x = 0; x < len; x++) 97 | { 98 | if(pos == CONSOLE_WIDTH * CONSOLE_HEIGHT) 99 | { 100 | /* Need to scroll the buffer */ 101 | move_buffer(); 102 | } 103 | 104 | switch(buf[x]) 105 | { 106 | case '\r': 107 | case '\n': 108 | /* Add enough space to get to next line */ 109 | if(!(pos % CONSOLE_WIDTH)) 110 | { 111 | render_buffer[pos++] = ' '; 112 | } 113 | 114 | while(pos % CONSOLE_WIDTH) 115 | { 116 | render_buffer[pos++] = ' '; 117 | } 118 | 119 | /* Make sure we don't run down the end */ 120 | if(pos == CONSOLE_WIDTH * CONSOLE_HEIGHT) 121 | { 122 | move_buffer(); 123 | } 124 | 125 | break; 126 | case '\t': 127 | /* Add enough spaces to go to the next tab stop */ 128 | if(!(pos % TAB_WIDTH)) 129 | { 130 | render_buffer[pos++] = ' '; 131 | } 132 | 133 | while(pos % TAB_WIDTH) 134 | { 135 | render_buffer[pos++] = ' '; 136 | } 137 | 138 | /* Make sure we don't run down the end */ 139 | if(pos == CONSOLE_WIDTH * CONSOLE_HEIGHT) 140 | { 141 | move_buffer(); 142 | } 143 | break; 144 | default: 145 | /* Copy character over */ 146 | render_buffer[pos++] = buf[x]; 147 | break; 148 | } 149 | } 150 | 151 | /* Cap off the end! */ 152 | render_buffer[pos] = 0; 153 | 154 | /* Out to screen! */ 155 | if(render_now == RENDER_AUTOMATIC) 156 | { 157 | __console_render(); 158 | } 159 | 160 | /* Always write all */ 161 | return len; 162 | } 163 | 164 | /** 165 | * @brief Structure used for hooking console commands to stdio 166 | */ 167 | static stdio_t console_calls = { 168 | 0, 169 | __console_write, 170 | 0 171 | }; 172 | 173 | /** 174 | * @brief Initialize the console 175 | * 176 | * Initialize the console system. This will initialize the video properly, so 177 | * a call to the display_init() fuction is not necessary. 178 | */ 179 | void console_init() 180 | { 181 | /* In case they initialized the display already */ 182 | display_close(); 183 | display_init( RESOLUTION_320x240, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE ); 184 | 185 | render_buffer = malloc(CONSOLE_SIZE); 186 | 187 | console_clear(); 188 | console_set_render_mode(RENDER_AUTOMATIC); 189 | 190 | /* Register ourselves with newlib */ 191 | hook_stdio_calls( &console_calls ); 192 | } 193 | 194 | /** 195 | * @brief Close the console 196 | * 197 | * Free the console system. This will clean up any dynamic memry that was in 198 | * use. 199 | */ 200 | void console_close() 201 | { 202 | if(render_buffer) 203 | { 204 | /* Nuke the console buffer */ 205 | free(render_buffer); 206 | render_buffer = 0; 207 | } 208 | 209 | /* Unregister ourselves from newlib */ 210 | unhook_stdio_calls(); 211 | } 212 | 213 | /** 214 | * @brief Clear the console 215 | * 216 | * Clear the console and set the virtual cursor back to the top left. 217 | */ 218 | void console_clear() 219 | { 220 | if(!render_buffer) { return; } 221 | 222 | /* Force fflush not to draw regardless */ 223 | int render = render_now; 224 | render_now = RENDER_MANUAL; 225 | 226 | /* Flush the stdout so that we don't get data after the clear */ 227 | fflush( stdout ); 228 | 229 | /* Return to original */ 230 | render_now = render; 231 | 232 | /* Remove all data */ 233 | memset(render_buffer, 0, CONSOLE_SIZE); 234 | 235 | /* Should we display? */ 236 | if(render_now == RENDER_AUTOMATIC) 237 | { 238 | __console_render(); 239 | } 240 | } 241 | 242 | /** 243 | * @brief Helper function to render the console 244 | */ 245 | static void __console_render() 246 | { 247 | if(!render_buffer) { return; } 248 | 249 | static display_context_t dc = 0; 250 | 251 | /* Wait until we get a valid context */ 252 | while(!(dc = display_lock())); 253 | 254 | /* Background color! */ 255 | graphics_fill_screen( dc, 0 ); 256 | 257 | for(int y = 0; y < CONSOLE_HEIGHT; y++) 258 | { 259 | for(int x = 0; x < CONSOLE_WIDTH; x++) 260 | { 261 | char t_buf = render_buffer[y * CONSOLE_WIDTH + x]; 262 | 263 | if(t_buf == 0) 264 | { 265 | display_show(dc); 266 | return; 267 | } 268 | 269 | /* Draw to the screen using the forecolor and backcolor set in the graphics 270 | * subsystem */ 271 | graphics_draw_character( dc, 20 + 8 * x, 16 + 8 * y, t_buf ); 272 | } 273 | } 274 | 275 | display_show(dc); 276 | } 277 | 278 | /** 279 | * @brief Render the console 280 | * 281 | * Render the console to the screen. This should be called when in manual 282 | * rendering mode to display the console to the screen. In automatic mode 283 | * it is not necessary to call. 284 | * 285 | * The color that is used to draw the text can be set using #graphics_set_color. 286 | */ 287 | void console_render() 288 | { 289 | /* Ensure data is flushed before rendering */ 290 | fflush( stdout ); 291 | 292 | /* Render now */ 293 | __console_render(); 294 | } 295 | 296 | /** @} */ /* console */ 297 | -------------------------------------------------------------------------------- /tools/mkdfs/mkdfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "dragonfs.h" 11 | #include "dfsinternal.h" 12 | 13 | #if BYTE_ORDER == BIG_ENDIAN 14 | #define SWAPLONG(i) (i) 15 | #else 16 | #define SWAPLONG(i) (((uint32_t)(i & 0xFF000000) >> 24) | ((uint32_t)(i & 0x00FF0000) >> 8) | ((uint32_t)(i & 0x0000FF00) << 8) | ((uint32_t)(i & 0x000000FF) << 24)) 17 | #endif 18 | 19 | uint8_t *dfs = NULL; 20 | uint32_t fs_size = 0; 21 | 22 | /* Offset from start of filesystem */ 23 | inline uint32_t sector_offset(void *sector) 24 | { 25 | uint32_t x = (uint8_t *)sector - dfs; 26 | 27 | return x; 28 | } 29 | 30 | inline void *sector_to_memory(uint32_t offset) 31 | { 32 | return (void *)(dfs + offset); 33 | } 34 | 35 | /* Add a new sector to the filesystem, return that sector pointer */ 36 | uint32_t new_sector() 37 | { 38 | void *end; 39 | 40 | if(!dfs) 41 | { 42 | dfs = malloc(SECTOR_SIZE); 43 | fs_size = SECTOR_SIZE; 44 | 45 | end = dfs; 46 | } 47 | else 48 | { 49 | dfs = realloc(dfs, fs_size + SECTOR_SIZE); 50 | 51 | end = dfs + fs_size; 52 | fs_size += SECTOR_SIZE; 53 | } 54 | 55 | /* Zero out last bytes */ 56 | memset(end, 0, SECTOR_SIZE); 57 | 58 | return sector_offset(end); 59 | } 60 | 61 | void kill_fs() 62 | { 63 | if(dfs) 64 | { 65 | free(dfs); 66 | } 67 | } 68 | 69 | void print_help(const char * const prog_name) 70 | { 71 | fprintf(stderr, "Usage: %s \n", prog_name); 72 | fprintf(stderr, " where is the resulting filesystem image\n"); 73 | fprintf(stderr, " and is the directory (including subdirectories) to include\n"); 74 | } 75 | 76 | uint32_t add_file(const char * const file, uint32_t *size) 77 | { 78 | uint32_t first_sector = 0; 79 | uint32_t cur_sector = 0; 80 | FILE *fp; 81 | 82 | printf("Adding '%s' to filesystem image.\n", file); 83 | 84 | fp = fopen(file, "r"); 85 | 86 | if(!fp) 87 | { 88 | fprintf(stderr, "Cannot open file '%s' for read!\n", file); 89 | return 0; 90 | } 91 | 92 | /* Start off fresh */ 93 | *size = 0; 94 | 95 | for(;;) 96 | { 97 | uint8_t t_buf[SECTOR_PAYLOAD]; 98 | 99 | int num_read = fread(t_buf, 1, SECTOR_PAYLOAD, fp); 100 | 101 | if(num_read < 0) 102 | { 103 | /* Wat? */ 104 | fprintf(stderr, "Cannot add all contents of file '%s' to filesystem!\n", file); 105 | fclose(fp); 106 | return 0; 107 | } 108 | 109 | if(num_read > 0) 110 | { 111 | file_entry_t *tmp_sector = 0; 112 | uint32_t new_node = new_sector(); 113 | 114 | tmp_sector = sector_to_memory(new_node); 115 | tmp_sector->next_sector = 0; // Ensure that if this is the last one, we don't reference wrong 116 | memcpy(tmp_sector->data, t_buf, num_read); 117 | 118 | /* Remember how many bytes we read in */ 119 | *size += num_read; 120 | 121 | if(cur_sector) 122 | { 123 | tmp_sector = sector_to_memory(cur_sector); 124 | tmp_sector->next_sector = SWAPLONG(new_node); 125 | } 126 | 127 | cur_sector = new_node; 128 | 129 | if(!first_sector) 130 | { 131 | /* Remember first sector in */ 132 | first_sector = new_node; 133 | } 134 | } 135 | else 136 | { 137 | /* Done! */ 138 | break; 139 | } 140 | } 141 | 142 | return first_sector; 143 | } 144 | 145 | uint32_t add_directory(const char * const path) 146 | { 147 | directory_entry_t *tmp_entry; 148 | uint32_t first_entry = 0; 149 | uint32_t cur_entry = 0; 150 | DIR *dirp; 151 | struct dirent *dp; 152 | 153 | if((dirp = opendir(path)) == NULL) 154 | { 155 | return 0; 156 | } 157 | 158 | do { 159 | if((dp = readdir(dirp)) != NULL) 160 | { 161 | if(strcmp(dp->d_name, ".") == 0) 162 | { 163 | /* Ignore */ 164 | } 165 | else if(strcmp(dp->d_name, "..") == 0) 166 | { 167 | /* Ignore */ 168 | } 169 | else 170 | { 171 | char *file = malloc(strlen(path) + strlen(dp->d_name) + 2); 172 | struct stat stats; 173 | 174 | if(!file) 175 | { 176 | /* Out of memory */ 177 | return 0; 178 | } 179 | 180 | strcpy(file, path); 181 | 182 | /* Only add a / if there isn't one */ 183 | if(path[strlen(path) - 1] != '/') 184 | { 185 | strcat(file, "/"); 186 | } 187 | 188 | strcat(file, dp->d_name); 189 | 190 | /* Figure out if it is a directory or regular (windows doesn't include d_type in dirent) */ 191 | stat( file, &stats ); 192 | 193 | if(S_ISREG(stats.st_mode)) 194 | { 195 | uint32_t new_entry = new_sector(); 196 | uint32_t file_size = 0; 197 | 198 | tmp_entry = sector_to_memory(new_entry); 199 | tmp_entry->next_entry = 0; 200 | 201 | /* Copy over filename */ 202 | strncpy(tmp_entry->path, dp->d_name, MAX_FILENAME_LEN); 203 | tmp_entry->path[MAX_FILENAME_LEN] = 0; 204 | 205 | uint32_t new_file = add_file(file, &file_size); 206 | 207 | if(!new_file) 208 | { 209 | free(file); 210 | return 0; 211 | } 212 | 213 | tmp_entry = sector_to_memory(new_entry); 214 | tmp_entry->file_pointer = SWAPLONG(new_file); 215 | 216 | tmp_entry->flags = SWAPLONG(((FLAGS_FILE << 24) | (file_size & 0x00FFFFFF))); 217 | 218 | if(cur_entry) 219 | { 220 | /* Link up! */ 221 | tmp_entry = sector_to_memory(cur_entry); 222 | tmp_entry->next_entry = SWAPLONG(new_entry); 223 | } 224 | 225 | /* This is now the current working entry */ 226 | cur_entry = new_entry; 227 | } 228 | else if(S_ISDIR(stats.st_mode)) 229 | { 230 | uint32_t new_entry = new_sector(); 231 | 232 | tmp_entry = sector_to_memory(new_entry); 233 | 234 | tmp_entry->flags = SWAPLONG(FLAGS_DIR << 24); /* Size doesn't matter for directories */ 235 | tmp_entry->next_entry = 0; 236 | 237 | /* Copy over filename */ 238 | strncpy(tmp_entry->path, dp->d_name, MAX_FILENAME_LEN); 239 | tmp_entry->path[MAX_FILENAME_LEN] = 0; 240 | 241 | uint32_t new_directory = add_directory(file); 242 | 243 | if(!new_directory) 244 | { 245 | free(file); 246 | return 0; 247 | } 248 | 249 | tmp_entry = sector_to_memory(new_entry); 250 | tmp_entry->file_pointer = SWAPLONG(new_directory); 251 | 252 | if(cur_entry) 253 | { 254 | /* Link up! */ 255 | tmp_entry = sector_to_memory(cur_entry); 256 | tmp_entry->next_entry = SWAPLONG(new_entry); 257 | } 258 | 259 | /* This is now the current working entry */ 260 | cur_entry = new_entry; 261 | } 262 | 263 | free(file); 264 | 265 | if(!first_entry) 266 | { 267 | /* Return pointer to first file on list */ 268 | first_entry = cur_entry; 269 | } 270 | } 271 | } 272 | } while (dp != NULL); 273 | 274 | closedir(dirp); 275 | 276 | /* Will return 0 if we don't find any entries (don't support directories without files) */ 277 | return first_entry; 278 | } 279 | 280 | int main(int argc, char *argv[]) 281 | { 282 | if(argc != 3) 283 | { 284 | print_help(argv[0]); 285 | return -1; 286 | } 287 | 288 | /* Add in identifier */ 289 | directory_entry_t *id = sector_to_memory(new_sector()); 290 | 291 | if(!id) 292 | { 293 | fprintf(stderr, "Out of memory!\n"); 294 | 295 | return -1; 296 | } 297 | 298 | id->flags = SWAPLONG(FLAGS_ID); 299 | id->next_entry = SWAPLONG(NEXTENTRY_ID); 300 | strcpy(id->path, "DragonFS 1.0"); 301 | 302 | if(!add_directory(argv[2])) 303 | { 304 | /* Error adding directory */ 305 | fprintf(stderr, "Error creating filesystem.\n"); 306 | 307 | kill_fs(); 308 | 309 | return -1; 310 | } 311 | 312 | /* Write out filesystem */ 313 | FILE *fp = fopen(argv[1], "w"); 314 | 315 | if(!fp) 316 | { 317 | /* Error writing file out */ 318 | fprintf(stderr, "Error opening '%s' for writing.\n", argv[1]); 319 | 320 | kill_fs(); 321 | } 322 | 323 | fwrite(dfs, 1, fs_size, fp); 324 | fclose(fp); 325 | 326 | kill_fs(); 327 | 328 | return 0; 329 | } 330 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file timer.c 3 | * @brief Timer Subsystem 4 | * @ingroup timer 5 | */ 6 | #include 7 | #include "libdragon.h" 8 | #include "regsinternal.h" 9 | 10 | /** 11 | * @defgroup timer Timer Subsystem 12 | * @ingroup libdragon 13 | * @brief Interface to the timer module in the MIPS r4300 processor. 14 | * 15 | * The timer subsystem allows code to receive a callback after a specified 16 | * number of ticks or microseconds. It interfaces with the MIPS 17 | * coprocessor 0 to handle the timer interrupt and provide useful timing 18 | * services. 19 | * 20 | * Before attempting to use the timer subsystem, code should call #timer_init. 21 | * After the timer subsystem has been initialized, a new one-shot or 22 | * continuous timer can be created with #new_timer. To remove an expired 23 | * one-shot timer or a recurring timer, use #delete_timer. To temporarily 24 | * stop a timer, use #stop_timer. To restart a stopped timer or an expired 25 | * one-shot timer, use #start_timer. Once code no longer needs the timer 26 | * subsystem, a call to #timer_close will free all continuous timers and shut 27 | * down the timer subsystem. Note that timers removed with #stop_timer or 28 | * expired one-short timers will not be removed automatically and are the 29 | * responsibility of the calling code to be freed, regardless of a call to 30 | * #timer_close. 31 | * @{ 32 | */ 33 | 34 | /** @brief Internal linked list of timers */ 35 | static timer_link_t *TI_timers = 0; 36 | /** @brief Total ticks elapsed since timer subsystem initialization */ 37 | static long long total_ticks; 38 | 39 | /** 40 | * @brief Read the count out of the count register 41 | * 42 | * @param[out] x 43 | * Variable to place count into 44 | */ 45 | #define read_count(x) asm volatile("mfc0 %0,$9\n\t nop \n\t" : "=r" (x) : ) 46 | /** 47 | * @brief Write the count to the count register 48 | * 49 | * @param[in] x 50 | * Value to write into the count register 51 | */ 52 | #define write_count(x) asm volatile("mtc0 %0,$9\n\t nop \n\t" : : "r" (x) ) 53 | /** 54 | * @brief Set the compare register 55 | * 56 | * This sets up the compare register so that when the count register equals the compare 57 | * register, an interrupt will be generated. 58 | * 59 | * @param[in] x 60 | * Value to write into the compare register 61 | */ 62 | #define write_compare(x) asm volatile("mtc0 %0,$11\n\t nop \n\t" : : "r" (x) ) 63 | 64 | /** 65 | * @brief Process linked list of timers 66 | * 67 | * Walk the linked list of timers and call the callbacks of any that 68 | * have expired. 69 | * 70 | * @note This function will remove one-shot timers from the list after 71 | * they have fired. 72 | * 73 | * @param[in] head 74 | * Head of the linked list of timers 75 | * 76 | * @retval 1 The list needs reprocessing 77 | * @retval 0 All timer operations were handled successfully 78 | */ 79 | static int __proc_timers(timer_link_t * head) 80 | { 81 | timer_link_t *last = 0; 82 | int smallest = 0x3FFFFFFF; // ~ 22.9 secs 83 | int start, now; 84 | 85 | read_count(start); 86 | total_ticks += start; 87 | 88 | while (head) 89 | { 90 | head->left -= start; 91 | // within ~5us? 92 | if (head->left < 234) 93 | { 94 | /* yes - timed out, do callback */ 95 | head->ovfl = head->left; 96 | if (head->callback) 97 | head->callback(head->ovfl); 98 | 99 | /* reset ticks if continuous */ 100 | if (head->flags & TF_CONTINUOUS) 101 | { 102 | head->left = head->set + head->ovfl; 103 | if (head->left < smallest) 104 | smallest = head->left; 105 | last = head; 106 | } 107 | else 108 | { 109 | /* one-shot, remove from list */ 110 | if (last) 111 | last->next = head->next; 112 | else 113 | TI_timers = head->next; 114 | } 115 | } 116 | else 117 | { 118 | /* no, just check if remaining time is smallest */ 119 | if (head->left < smallest) 120 | smallest = head->left; 121 | last = head; 122 | } 123 | 124 | /* Go to next */ 125 | head = head->next; 126 | } 127 | 128 | /* check if shortest time left < 5us */ 129 | read_count(now); 130 | if (smallest < (now - start + 234)) 131 | { 132 | total_ticks += (now - start); 133 | write_count(now - start); 134 | return 1; // reprocess the list 135 | } 136 | /* set compare to shortest time left */ 137 | write_count(0); 138 | write_compare(smallest - (now - start)); 139 | return 0; // exit timer callback 140 | } 141 | 142 | /** 143 | * @brief Timer callback function 144 | * 145 | * This function is called by the interrupt controller whenever 146 | * compare == count. 147 | */ 148 | static void timer_callback(void) 149 | { 150 | if (TI_timers) 151 | { 152 | while (__proc_timers(TI_timers)) ; 153 | } 154 | else 155 | { 156 | int now; 157 | read_count(now); 158 | total_ticks += now; 159 | write_count(0); 160 | write_compare(0x7FFFFFFF); 161 | } 162 | } 163 | 164 | /** 165 | * @brief Initialize the timer subsystem 166 | */ 167 | void timer_init(void) 168 | { 169 | total_ticks = 0; 170 | write_count(0); 171 | write_compare(0x7FFFFFFF); 172 | register_TI_handler(timer_callback); 173 | } 174 | 175 | /** 176 | * @brief Create a new timer and add to list 177 | * 178 | * @param[in] ticks 179 | * Number of ticks before the timer should fire 180 | * @param[in] flags 181 | * Timer flags. See #TF_ONE_SHOT and #TF_CONTINUOUS 182 | * @param[in] callback 183 | * Callback function to call when the timer expires 184 | * 185 | * @return A pointer to the timer structure created 186 | */ 187 | timer_link_t *new_timer(int ticks, int flags, void (*callback)(int ovfl)) 188 | { 189 | timer_link_t *timer = malloc(sizeof(timer_link_t)); 190 | if (timer) 191 | { 192 | timer->left = ticks; 193 | timer->set = ticks; 194 | timer->flags = flags; 195 | timer->callback = callback; 196 | 197 | disable_interrupts(); 198 | 199 | timer->next = TI_timers; 200 | TI_timers = timer; 201 | if (timer->next == 0) 202 | { 203 | /* first timer added to list */ 204 | write_count(0); 205 | write_compare(timer->left); 206 | } 207 | else 208 | timer_callback(); // force processing the timers 209 | 210 | enable_interrupts(); 211 | } 212 | return timer; 213 | } 214 | 215 | /** 216 | * @brief Start a timer not currently in the list 217 | * 218 | * @param[in] timer 219 | * Pointer to timer structure to reinsert and start 220 | * @param[in] ticks 221 | * Number of ticks before the timer should fire 222 | * @param[in] flags 223 | * Timer flags. See #TF_ONE_SHOT and #TF_CONTINUOUS 224 | * @param[in] callback 225 | * Callback function to call when the timer expires 226 | */ 227 | void start_timer(timer_link_t *timer, int ticks, int flags, void (*callback)(int ovfl)) 228 | { 229 | if (timer) 230 | { 231 | timer->left = ticks; 232 | timer->set = ticks; 233 | timer->flags = flags; 234 | timer->callback = callback; 235 | 236 | disable_interrupts(); 237 | 238 | timer->next = TI_timers; 239 | TI_timers = timer; 240 | if (timer->next == 0) 241 | { 242 | /* first timer added to list */ 243 | write_count(0); 244 | write_compare(timer->left); 245 | } 246 | else 247 | timer_callback(); // force processing the timers 248 | 249 | enable_interrupts(); 250 | } 251 | } 252 | 253 | /** 254 | * @brief Stop a timer and remove it from the list 255 | * 256 | * @note This function does not free a timer structure, use #delete_timer 257 | * to do this. 258 | * 259 | * @param[in] timer 260 | * Timer structure to stop and remove 261 | */ 262 | void stop_timer(timer_link_t *timer) 263 | { 264 | timer_link_t *head; 265 | timer_link_t *last = 0; 266 | 267 | if (timer) 268 | { 269 | disable_interrupts(); 270 | head = TI_timers; 271 | while (head) 272 | { 273 | if (head == timer) 274 | { 275 | /* remove from list */ 276 | if (last) 277 | last->next = head->next; 278 | else 279 | TI_timers = head->next; 280 | 281 | break; 282 | } 283 | 284 | last = head; 285 | head = head->next; 286 | } 287 | enable_interrupts(); 288 | } 289 | } 290 | 291 | /** 292 | * @brief Remove a timer from the list and delete it 293 | * 294 | * @param[in] timer 295 | * Timer structure to stop, remove and free 296 | */ 297 | void delete_timer(timer_link_t *timer) 298 | { 299 | if (timer) 300 | { 301 | stop_timer(timer); 302 | free(timer); 303 | } 304 | } 305 | 306 | /** 307 | * @brief Free and close the timer subsystem 308 | * 309 | * This function will ensure all recurring timers are deleted from the list 310 | * before closing. One-shot timers that have expired will need to be 311 | * manually deleted with #delete_timer. 312 | */ 313 | void timer_close(void) 314 | { 315 | disable_interrupts(); 316 | 317 | unregister_TI_handler(timer_callback); 318 | 319 | timer_link_t *head = TI_timers; 320 | while (head) 321 | { 322 | timer_link_t *last = head; 323 | head = head->next; 324 | 325 | if (last->flags & TF_CONTINUOUS) 326 | { 327 | /* Only free if it is a continuous timer as one-shot timers are 328 | * freed by the user. If we free a timer here, the user will 329 | * never know if a one shot expired and needs to be removed or 330 | * was removed automatically by timer_close. We avoid this race 331 | * condition by ensuring that the timer system never frees a 332 | * one shot timer. 333 | */ 334 | free(last); 335 | } 336 | } 337 | TI_timers = 0; 338 | enable_interrupts(); 339 | } 340 | 341 | /** 342 | * @brief Return total ticks since timer was initialized 343 | * 344 | * @return Then number of ticks since the timer was initialized 345 | */ 346 | long long timer_ticks(void) 347 | { 348 | disable_interrupts(); 349 | timer_callback(); // force processing the timers 350 | enable_interrupts(); 351 | return total_ticks; 352 | } 353 | 354 | /** @} */ 355 | -------------------------------------------------------------------------------- /examples/tlut/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "system.c" 10 | #include "controls.c" 11 | 12 | // SYSTEM 13 | static sprite_t *graph[19]; // sprites 14 | static display_context_t disp = 0; // screen 15 | char tStr[32]; // text 16 | 17 | // INTERNAL FUNCTIONS 18 | uint8_t restore_type=1; 19 | int error=-1; 20 | 21 | // FPS 22 | int16_t fps_tick=0; 23 | int16_t fps_sec=0; 24 | 25 | // 4bit (15 colors used) 26 | uint16_t palette_0[16] = { 0,19,29791,48609,21141,59193,22851,2115,31303,45961,24577,32769,10573,56585,47105,0 }; 27 | uint16_t palette_copy[16] = { 0,19,29791,48609,21141,59193,22851,2115,31303,45961,24577,32769,10573,56585,47105,0 }; 28 | 29 | // VARIABLES 30 | uint16_t color; 31 | uint16_t color_buf=0; 32 | int color_sel=0; 33 | 34 | int mouse_x; 35 | int mouse_y; 36 | 37 | uint8_t r; 38 | uint8_t g; 39 | uint8_t b; 40 | uint8_t color_text; 41 | 42 | int backup_num; 43 | int backup_color; 44 | 45 | int start_rotate=0; 46 | int rotate_direction=0; 47 | int rotate_counter=0; 48 | 49 | // PROGRAM 50 | int main(void) 51 | { 52 | // INTERRUPTS 53 | init_interrupts(); 54 | 55 | // VIDEO 56 | display_init( RESOLUTION_320x240, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE ); 57 | 58 | // SYSTEM INIT 59 | dfs_init(DFS_DEFAULT_LOCATION); 60 | rdp_init(); 61 | controller_init(); 62 | timer_init(); 63 | 64 | // FPS 65 | new_timer(TIMER_TICKS(1000000), TF_CONTINUOUS, update_counter); 66 | 67 | // INIT RAND 68 | srand(timer_ticks() & 0x7FFFFFFF); 69 | 70 | // BASIC RDP CONFIG 71 | uint64_t RDP_CONFIG = ATOMIC_PRIM | ALPHA_DITHER_SEL_NO_DITHER | RGB_DITHER_SEL_NO_DITHER; 72 | 73 | int i=0; 74 | char sprite_path[32]; 75 | 76 | // LOAD SPRITES 77 | for(i=0;i<19;i++) 78 | { 79 | sprintf(sprite_path,"/%d.sprite",i); 80 | graph[i] = load_sprite(sprite_path); 81 | 82 | if (graph[i]==0) 83 | { 84 | error=i+1; 85 | break; 86 | } 87 | } 88 | 89 | // LOOP 90 | while(1) 91 | { 92 | // WAIT BUFFER 93 | while( !(disp = display_lock()) ); 94 | 95 | // SET CLIPPING 96 | rdp_attach_display(disp); 97 | rdp_sync(SYNC_PIPE); 98 | rdp_set_clipping(0,0,320,240); 99 | 100 | // CLEAN BUFFER: optional, if the full screen is covered by a scroll restore_type can be set to 0 101 | if (restore_type==1) 102 | { 103 | rdp_enable_primitive_fill(); 104 | rdp_set_fill_color(48,0,72,255); 105 | rdp_draw_filled_rectangle(0,0,319,239); 106 | } 107 | 108 | // SCAN CONTROLS 109 | update_controls(); 110 | 111 | // RDP TEXTURE MODE 112 | rdp_texture_copy(RDP_CONFIG); 113 | 114 | // DRAW COLOR TABLE 115 | for(i=0;i<16;i++) 116 | { 117 | rdp_load_texture(graph[i]); // load to TMEM 118 | rdp_draw_sprite(115,30+(i*8),0); // draw 119 | } 120 | 121 | // Cheap: RDP seems to work in parallel with CPU 122 | // We force the last texture of the table to be drawn with the CPU to ensure the framebuffer we are going to read is updated 123 | graphics_draw_sprite(disp,115,158,graph[16]); 124 | 125 | // MOUSE USES JOYSTICK 126 | if (joystick_x<-4 || joystick_x>4) { mouse_x+=joystick_x/5; } 127 | if (joystick_y<-4 || joystick_y>4) { mouse_y-=joystick_y/5; } 128 | 129 | if (mouse_x<0) { mouse_x=0; } 130 | if (mouse_x>304) { mouse_x=304; } 131 | if (mouse_y<0) { mouse_y=0; } 132 | if (mouse_y>224) { mouse_y=224; } 133 | 134 | // GET PIXEL 135 | if (mouse_x>115) 136 | { 137 | color=get_pixel(disp,mouse_x,mouse_y); 138 | 139 | // Extract 140 | uint8_t r1 = (color & 0xF800) >> 11; // 63488 141 | uint8_t g1 = (color & 0x7C0) >> 6; // 1984 142 | uint8_t b1 = (color & 0x3E) >> 1; // 62 143 | 144 | // Expand to 8bit 145 | r = r1 << 3; 146 | g = g1 << 3; 147 | b = b1 << 3; 148 | 149 | if (mouse_x<297 && mouse_y>30 && mouse_y<166) 150 | { 151 | if (a_button>0) 152 | color_buf=get_pixel(disp,mouse_x,mouse_y); 153 | } 154 | else 155 | r = g = b = 0; 156 | 157 | } 158 | 159 | // SMALL BOX WITH THE COLOR SELECTED 160 | graphics_draw_box(disp, 40, 50, 16, 16, color_buf); 161 | 162 | // CONTROL PALETTE ENTRY 163 | if (a_button==1) 164 | { 165 | // 0..7 166 | if (mouse_y>174 && mouse_y<174+24) 167 | { 168 | for (i=1;i<8;i++) 169 | { 170 | if (mouse_x>49+(i*32) && mouse_x<49+24+(i*32)) 171 | { 172 | if (palette_0[i]!=color_buf) 173 | { 174 | backup_color=palette_0[i]; 175 | palette_0[i]=color_buf; 176 | backup_num=i; 177 | } 178 | } 179 | } 180 | } 181 | 182 | // 8..15 183 | if (mouse_y>206 && mouse_y<206+24) 184 | { 185 | for (i=0;i<8;i++) 186 | { 187 | if (mouse_x>49+(i*32) && mouse_x<49+24+(i*32)) 188 | { 189 | if (palette_0[i+8]!=color_buf) 190 | { 191 | backup_color=palette_0[i+8]; 192 | palette_0[i+8]=color_buf; 193 | backup_num=i+8; 194 | } 195 | } 196 | } 197 | } 198 | 199 | } 200 | 201 | // STOP PALETTE ROTATION 202 | if (r_button==1) 203 | { 204 | if (start_rotate==2) 205 | { 206 | start_rotate=0; 207 | start_button=1; 208 | } 209 | } 210 | 211 | // RESET CUSTOM PALETTE 212 | if (start_button==1) 213 | { 214 | for(i=0;i<16;i++) 215 | { 216 | palette_0[i]=palette_copy[i]; 217 | } 218 | } 219 | 220 | // REVERSE LAST COLOR EDITED 221 | if (z_button==1) 222 | palette_0[backup_num]=backup_color; 223 | 224 | // START PALETTE ROTATION 225 | if (l_button==1) 226 | { 227 | if (start_rotate==0) 228 | start_rotate=1; 229 | } 230 | 231 | if (start_rotate==1) 232 | { 233 | rotate_counter=0; 234 | rotate_direction=0; 235 | start_rotate=2; 236 | } 237 | 238 | if (start_rotate==2) 239 | { 240 | 241 | if (rotate_direction==0) 242 | { 243 | rotate_counter+=4; 244 | if (rotate_counter>164) 245 | rotate_direction=1; 246 | } 247 | else 248 | { 249 | rotate_counter-=4; 250 | if (rotate_counter<4) 251 | { 252 | rotate_direction=0; 253 | rotate_counter=0; 254 | } 255 | } 256 | 257 | palette_0[1]=graphics_make_color(0,0,255-rotate_counter,255); // blue 258 | palette_0[10]=graphics_make_color(192-rotate_counter,0,0,255); // red 259 | palette_0[11]=graphics_make_color(255-rotate_counter,0,0,255); // red 1 260 | palette_0[14]=graphics_make_color(255-rotate_counter,0,0,255); // red 2 261 | } 262 | 263 | // PALETTE SCREEN BOX 264 | for(i=0;i<8;i++) 265 | { 266 | if (i!=0) 267 | graphics_draw_box(disp, 49+(i*32), 174, 24, 24, palette_0[i]); 268 | 269 | if (i!=7) 270 | graphics_draw_box(disp, 49+(i*32), 206, 24, 24, palette_0[i+8]); 271 | } 272 | 273 | // cache must be invalidated for palette updates 274 | data_cache_hit_writeback_invalidate( palette_0, 16*2 ); // 16 colors, int16 = 2 bytes 275 | 276 | // DRAW ALUCARD SPRITE 277 | rdp_texture_cycle(0,0,RDP_CONFIG | EN_TLUT); // 1cycle because is going to be 2x size, enable tlut for palettes 278 | rdp_load_palette(0,15,palette_0); // upload starting on palette 0, 15 colors upload, point to the palette struct 279 | rdp_load_texture(graph[18]); 280 | rdp_draw_sprite_scaled(45,70,2.0,2.0,0); // scaled 2X 281 | 282 | // THEN DRAW MOUSE 283 | rdp_texture_copy(RDP_CONFIG); // we disable tlut & we don't need 1cycle here 284 | rdp_load_texture(graph[17]); 285 | rdp_draw_sprite(mouse_x, mouse_y, 0 ); 286 | 287 | // RDP IS DONE 288 | rdp_detach_display(); 289 | 290 | // FRAMERATE 291 | if(framerate_refresh==1) 292 | { 293 | fps_sec=fps_tick; 294 | fps_tick=0; 295 | framerate_refresh=0; 296 | } 297 | fps_tick++; 298 | 299 | // TEXT 300 | sprintf(tStr,"FPS: %d\n",fps_sec); 301 | graphics_draw_text(disp,40,10,tStr); 302 | 303 | sprintf(tStr, "R: %d\n",r); 304 | graphics_draw_text( disp, 40, 20, tStr ); 305 | 306 | sprintf(tStr, "G: %d\n",g); 307 | graphics_draw_text( disp, 40, 30, tStr ); 308 | 309 | sprintf(tStr, "B: %d\n",b); 310 | graphics_draw_text( disp, 40, 40, tStr ); 311 | 312 | if (error>0) 313 | { 314 | sprintf(tStr,"FILE: %d\n",error-1); 315 | graphics_draw_text(disp,40,200,tStr); 316 | } 317 | 318 | // FRAME READY 319 | display_show(disp); 320 | } 321 | } -------------------------------------------------------------------------------- /tools/n64tool.c: -------------------------------------------------------------------------------- 1 | /* 2 | n64tool V1.0, a program used to append an n64 header to an arbitrary 3 | sized Nintendo64 binary. 4 | Copyright (C) 2009 Shaun Taylor (dragonminded@dragonminded.com) 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define WRITE_SIZE 1024 27 | 28 | #define TITLE_LOC 32 29 | #define TITLE_SIZE 20 30 | #define DEF_TITLE "N64 Demo" 31 | 32 | #define STATE_NONE 0 33 | #define STATE_L 1 34 | #define STATE_H 2 35 | #define STATE_O 3 36 | #define STATE_S 4 37 | #define STATE_T 5 38 | 39 | /* Easier to write from here */ 40 | static int title[TITLE_SIZE]; 41 | static int wrote_title = 0; 42 | 43 | void print_usage(char *prog_name) 44 | { 45 | fprintf(stderr, "Usage: %s [-b] -l B/K/M -h -o -t <file> [[-s <offset>B/K/M] <file>]*\n\n", prog_name); 46 | fprintf(stderr, "This program appends a header to an arbitrary number of binaries,\n"); 47 | fprintf(stderr, "the first being an Nintendo64 binary and the rest arbitrary data.\n\n"); 48 | fprintf(stderr, "\t-b\t\tByteswap the resulting output.\n"); 49 | fprintf(stderr, "\t-l <size>\tForce output to <size> bytes.\n"); 50 | fprintf(stderr, "\t-h <file>\tUse <file> as header.\n"); 51 | fprintf(stderr, "\t-o <file>\tOutput is saved to <file>.\n"); 52 | fprintf(stderr, "\t-t <title>\tTitle of ROM.\n"); 53 | fprintf(stderr, "\t-s <offset>\tNext file starts at <offset> from top of memory. Offset must be 32bit aligned.\n"); 54 | fprintf(stderr, "\t\t\tB for byte offset.\n"); 55 | fprintf(stderr, "\t\t\tK for kilobyte offset.\n"); 56 | fprintf(stderr, "\t\t\tM for megabyte offset.\n"); 57 | } 58 | 59 | uint32_t get_file_size(FILE *fp) 60 | { 61 | int x = ftell(fp); 62 | uint32_t ret = 0; 63 | 64 | fseek(fp, 0, SEEK_END); 65 | ret = ftell(fp); 66 | fseek(fp, x, SEEK_SET); 67 | 68 | return ret; 69 | } 70 | 71 | int swap_bytes(uint8_t *buffer, int size) 72 | { 73 | if(size & 1 == 0) 74 | { 75 | /* Invalid, can only byteswap multiples of 2 */ 76 | return -1; 77 | } 78 | 79 | int i; 80 | 81 | for(i = 0; i < (size >> 1); i++) 82 | { 83 | int loc1 = i << 1; 84 | int loc2 = loc1 + 1; 85 | 86 | /* Easy peasy */ 87 | uint8_t temp = buffer[loc1]; 88 | buffer[loc1] = buffer[loc2]; 89 | buffer[loc2] = temp; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | int copy_file(FILE *dest, char *file, int byte_swap) 96 | { 97 | FILE *read_file = fopen(file, "rb"); 98 | uint8_t *buffer; 99 | 100 | if(!read_file) 101 | { 102 | fprintf(stderr, "Cannot open %s for reading!\n", file); 103 | return -1; 104 | } 105 | 106 | int fsize = get_file_size(read_file); 107 | int rsize = fsize; 108 | 109 | /* Should probably make this read in incriments, but whatever */ 110 | buffer = malloc(WRITE_SIZE); 111 | 112 | if(!buffer) 113 | { 114 | fprintf(stderr, "Out of memory!\n"); 115 | 116 | fclose(read_file); 117 | 118 | return -1; 119 | } 120 | 121 | /* Weird windows bug fix, plus this is the right way to do things */ 122 | while(fsize > 0) 123 | { 124 | /* Max 1K chunk */ 125 | int write_size = (fsize > WRITE_SIZE) ? WRITE_SIZE : fsize; 126 | fsize -= write_size; 127 | 128 | fread(buffer, 1, write_size, read_file); 129 | 130 | if(!wrote_title) 131 | { 132 | /* Pop title into header */ 133 | memcpy(buffer + TITLE_LOC, title, TITLE_SIZE); 134 | 135 | wrote_title = 1; 136 | } 137 | 138 | if(byte_swap) 139 | { 140 | if(swap_bytes(buffer, write_size)) 141 | { 142 | fprintf(stderr, "Invalid file size on %s. Should be multiple of 32bits!\n", file); 143 | 144 | free(buffer); 145 | fclose(read_file); 146 | 147 | return -1; 148 | } 149 | } 150 | 151 | fwrite(buffer, 1, write_size, dest); 152 | } 153 | 154 | free(buffer); 155 | fclose(read_file); 156 | 157 | return rsize; 158 | } 159 | 160 | int output_zeros(FILE *dest, int amount) 161 | { 162 | if(amount & 3 != 0) 163 | { 164 | /* Don't support odd word alignments */ 165 | return -1; 166 | } 167 | 168 | if(amount <= 0) 169 | { 170 | /* We are done */ 171 | return 0; 172 | } 173 | 174 | int i; 175 | 176 | for(i = 0; i < (amount >> 2); i++) 177 | { 178 | /* Write out a word at a time */ 179 | uint32_t byte = 0; 180 | 181 | fwrite(&byte, 1, 4, dest); 182 | } 183 | 184 | return 0; 185 | } 186 | 187 | int get_bytes(char *cur_arg) 188 | { 189 | int size = 0; 190 | 191 | /* Figure out if they mean bytes, kilobytes, megabytes */ 192 | char c = cur_arg[strlen(cur_arg)-1]; 193 | 194 | /* Blank last character to do an atoi */ 195 | char *temp = strdup(cur_arg); 196 | temp[strlen(temp)-1] = '\0'; 197 | 198 | /* Grab number */ 199 | size = atoi(temp); 200 | free(temp); 201 | 202 | /* Multiply out by byte amount */ 203 | switch(c) 204 | { 205 | case 'm': 206 | case 'M': 207 | size *= 1024; 208 | case 'k': 209 | case 'K': 210 | size *= 1024; 211 | case 'b': 212 | case 'B': 213 | break; 214 | default: 215 | /* Invalid! */ 216 | return -1; 217 | } 218 | 219 | return size; 220 | } 221 | 222 | int main(int argc, char *argv[]) 223 | { 224 | FILE *write_file = 0; 225 | char *header = 0; 226 | char *output = 0; 227 | int total_size = 0; 228 | int total_bytes = 0; 229 | int state = STATE_NONE; 230 | int byte_swap = 0; 231 | int i; 232 | 233 | /* Set default title */ 234 | memset(title, 0x20, TITLE_SIZE); 235 | memcpy(title, DEF_TITLE, (strlen(DEF_TITLE) > TITLE_SIZE) ? TITLE_SIZE : strlen(DEF_TITLE)); 236 | 237 | if(argc <= 1) 238 | { 239 | /* No way we can have just one argument or less */ 240 | print_usage(argv[0]); 241 | return -1; 242 | } 243 | 244 | for(i = 1; i < argc; i++) 245 | { 246 | char *cur_arg = argv[i]; 247 | 248 | switch(cur_arg[0]) 249 | { 250 | case '-': 251 | /* Option flag */ 252 | switch(cur_arg[1]) 253 | { 254 | case 'b': 255 | /* Byteswap output */ 256 | byte_swap = 1; 257 | break; 258 | case 'l': 259 | /* Size of resulting image */ 260 | state = STATE_L; 261 | break; 262 | case 'h': 263 | /* Header file */ 264 | if(!header) 265 | { 266 | state = STATE_H; 267 | } 268 | else 269 | { 270 | print_usage(argv[0]); 271 | return -1; 272 | } 273 | 274 | break; 275 | case 'o': 276 | /* Output file */ 277 | if(!output) 278 | { 279 | state = STATE_O; 280 | } 281 | else 282 | { 283 | print_usage(argv[0]); 284 | return -1; 285 | } 286 | break; 287 | case 's': 288 | /* Offset */ 289 | state = STATE_S; 290 | break; 291 | case 't': 292 | /* Title */ 293 | state = STATE_T; 294 | break; 295 | default: 296 | print_usage(argv[0]); 297 | return -1; 298 | } 299 | 300 | break; 301 | case '\0': 302 | /* Shouldn't happen */ 303 | fprintf(stderr, "Unexpected end of arguments!\n"); 304 | return -1; 305 | default: 306 | /* Standard argument */ 307 | switch(state) 308 | { 309 | case STATE_H: 310 | /* Get header file */ 311 | header = cur_arg; 312 | break; 313 | case STATE_O: 314 | /* Get output file */ 315 | output = cur_arg; 316 | break; 317 | case STATE_T: 318 | /* Grab title */ 319 | if(strlen(cur_arg) < 16) 320 | { 321 | /* Spaces for pretty printing */ 322 | memset(title, 0x20, TITLE_SIZE); 323 | memcpy(title, cur_arg, strlen(cur_arg)); 324 | } 325 | else 326 | { 327 | memcpy(title, cur_arg, TITLE_SIZE); 328 | } 329 | 330 | break; 331 | case STATE_S: 332 | /* Can't be here unless header and output set, and has to be at least 2 bytes. 333 | Also, they have to have at least one file output before they can skip bytes. */ 334 | if(!header || !output || strlen(cur_arg) < 2 || !total_bytes || !total_size) 335 | { 336 | print_usage(argv[0]); 337 | return -1; 338 | } 339 | 340 | int offset = get_bytes(cur_arg); 341 | 342 | if(offset < 0) 343 | { 344 | /* Invalid! */ 345 | print_usage(argv[0]); 346 | return -1; 347 | } 348 | 349 | /* Write out needed number of zeros */ 350 | int num_zeros = offset - total_bytes; 351 | 352 | if(output_zeros(write_file, num_zeros)) 353 | { 354 | fprintf(stderr, "Invalid offset to seek to!\n", output); 355 | return -1; 356 | } 357 | 358 | /* Same as total_bytes = offset */ 359 | total_bytes += num_zeros; 360 | 361 | break; 362 | case STATE_L: 363 | /* Just grab size */ 364 | total_size = get_bytes(cur_arg); 365 | 366 | if(total_size < 0) 367 | { 368 | /* Invalid! */ 369 | print_usage(argv[0]); 370 | return -1; 371 | } 372 | 373 | break; 374 | case STATE_NONE: 375 | /* Can't be here unless header and output set */ 376 | if(!header || !output || !total_size) 377 | { 378 | print_usage(argv[0]); 379 | return -1; 380 | } 381 | 382 | /* Is our output file open? */ 383 | if(!write_file) 384 | { 385 | write_file = fopen(output, "wb"); 386 | 387 | if(!write_file) 388 | { 389 | fprintf(stderr, "Cannot open %s for writing!\n", output); 390 | return -1; 391 | } 392 | 393 | int wrote = copy_file(write_file, header, byte_swap); 394 | 395 | /* Since write file wasn't open, we haven't written the header */ 396 | if(wrote < 0) 397 | { 398 | return -1; 399 | } 400 | else 401 | { 402 | /* Adjust final output size to reflect */ 403 | total_size -= wrote; 404 | } 405 | } 406 | 407 | /* Copy over file */ 408 | int copied = copy_file(write_file, cur_arg, byte_swap); 409 | 410 | if(copied < 0) 411 | { 412 | /* Error, exit */ 413 | return -1; 414 | } 415 | 416 | /* Keep track to be sure we align properly when they request a memory alignment */ 417 | total_bytes += copied; 418 | 419 | break; 420 | } 421 | 422 | /* Reset state */ 423 | state = STATE_NONE; 424 | 425 | break; 426 | } 427 | } 428 | 429 | if(!total_bytes) 430 | { 431 | printf("No input files, nothing written!\n"); 432 | /* Didn't write anything! */ 433 | } 434 | else 435 | { 436 | /* Pad to correct length */ 437 | int num_zeros = total_size - total_bytes; 438 | 439 | if(output_zeros(write_file, num_zeros)) 440 | { 441 | fprintf(stderr, "Couldn't pad image!\n", output); 442 | return -1; 443 | } 444 | 445 | fflush(write_file); 446 | fclose(write_file); 447 | } 448 | 449 | return 0; 450 | } 451 | --------------------------------------------------------------------------------