├── .gitattributes ├── .gitignore ├── Makefile └── src ├── _syscalls.h ├── _syscalls_o1.c ├── aligned_alloc.c ├── aligned_alloc.h ├── c_syscall.h ├── calctype.h ├── cselcd.c ├── cselcd.h ├── cselcd_imp.c ├── cselcd_imp.h ├── drz80.h ├── drz80.s ├── interrupt.c ├── interrupt.h ├── io.c ├── io.h ├── io_misc.h ├── keypad.c ├── keypad.h ├── lcd.c ├── lcd.h ├── main.c ├── main.h ├── mmu_mmap.c ├── mmu_mmap.h ├── navnet-defs.h ├── navnet-io.c ├── navnet-io.h ├── rtc.c ├── rtc.h ├── savestate.c ├── savestate.h ├── speedcontrol.c ├── speedcontrol.h ├── timer.c ├── timer.h ├── util.h ├── z_interrupt.c └── z_interrupt.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rom 2 | *.tns 3 | *.elf 4 | *.zehn 5 | roms/ 6 | roms/* 7 | build/ 8 | build/* 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEBUG ?= TRUE 2 | 3 | GCC = nspire-gcc 4 | AS = arm-none-eabi-as -mcpu=arm926ej-s # nspire-as 5 | GXX = nspire-g++ 6 | LD = nspire-ld 7 | GENZEHN = genzehn 8 | 9 | NSPIREIO ?= FALSE 10 | NAVNETIO ?= FALSE 11 | 12 | GCCFLAGS ?= 13 | GCCFLAGS += -Wall -W -marm # -include _nn_insert.h# -DKEYS_H # -mfloat-abi=softfp -mfpu=vfpv3 -nostdlib 14 | O1FLAGS = 15 | LDFLAGS = # -Wl,--nspireio # -Wl,-wrap,printf -Wl,-wrap,puts # -Wl,-wrap,printf -Wl,-wrap,puts#-Wl,-nostdlib -lndls -lsyscalls 16 | ZEHNFLAGS = --name "nspire-z80" --uses-lcd-blit false --240x320-support true 17 | 18 | SRC_DIR = src 19 | DEPLOY_DIR = 20 | 21 | ifeq ($(NSPIREIO),TRUE) 22 | LDFLAGS += -Wl,--nspireio 23 | GCCFLAGS += -DNO_LCD 24 | endif 25 | 26 | ifeq ($(NAVNETIO),TRUE) 27 | LDFLAGS += -Wl,-wrap,printf -Wl,-wrap,puts 28 | GCCFLAGS += -DUSE_NAVNETIO 29 | endif 30 | 31 | ifeq ($(DEBUG),FALSE) 32 | GCCFLAGS += -Os 33 | else 34 | GCCFLAGS += -O0 -g 35 | O1FLAGS += -O1 36 | endif 37 | 38 | OBJS = $(patsubst %.c, %.o, $(shell find $(SRC_DIR) -name \*.c)) 39 | OBJS += $(patsubst %.cpp, %.o, $(shell find $(SRC_DIR) -name \*.cpp)) 40 | OBJS += $(patsubst %.s, %.o, $(shell find $(SRC_DIR) -name \*.s)) 41 | EXE = nspire-z80 42 | DISTDIR = build 43 | vpath %.tns $(DISTDIR) 44 | vpath %.elf $(DISTDIR) 45 | 46 | all: $(EXE).tns 47 | 48 | $(DISTDIR)/%.o: $(SRC_DIR)/%.c 49 | $(GCC) $(GCCFLAGS) -c $< -o $@ 50 | 51 | $(DISTDIR)/%.o: $(SRC_DIR)/%.cpp 52 | $(GXX) $(GCCFLAGS) -c $< -o $@ 53 | 54 | $(DISTDIR)/%.o: $(SRC_DIR)/%.s 55 | $(AS) -c $< -o $@ 56 | 57 | $(DISTDIR)/%_o1.o: $(SRC_DIR)/%_o1.c 58 | $(GCC) $(GCCFLAGS) $(O1FLAGS) -c $< -o $@ 59 | 60 | 61 | $(EXE).elf: $(patsubst $(SRC_DIR)/%,$(DISTDIR)/%, $(OBJS)) 62 | mkdir -p $(DISTDIR) 63 | $(LD) $^ -o $@ $(LDFLAGS) 64 | 65 | $(EXE).tns: $(EXE).elf 66 | $(GENZEHN) --input $^ --output $@.zehn $(ZEHNFLAGS) 67 | make-prg $@.zehn $@ 68 | rm $@.zehn 69 | 70 | .PHONY: deploy 71 | 72 | deploy: $(EXE).tns 73 | NavNet_launcher.exe NavNet_upload.exe "$(shell wslpath -w $(EXE).tns)" $(EXE).tns 74 | 75 | clean: 76 | rm -f $(patsubst $(SRC_DIR)/%,$(DISTDIR)/%, $(OBJS)) $(EXE).tns $(EXE).elf $(EXE).tns.zehn 77 | -------------------------------------------------------------------------------- /src/_syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef _MALLOC_H 2 | #define _MALLOC_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void *_malloc(size_t size); 9 | void _free(void *ptr); 10 | scr_type_t _lcd_type(); 11 | size_t real_puts(const char *ptr); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/_syscalls_o1.c: -------------------------------------------------------------------------------- 1 | //#pragma GCC optimize ("-O1") 2 | 3 | #include "_syscalls.h" 4 | #include "c_syscall.h" 5 | #include 6 | 7 | void *_malloc(size_t size) { 8 | return (void *)wa_syscall1(e_malloc, size); 9 | } 10 | 11 | void _free(void *ptr) { 12 | wa_syscall1(e_free, (uintptr_t)ptr); 13 | } 14 | 15 | scr_type_t _lcd_type(){ 16 | return wa_syscall(e_nl_lcd_type); 17 | } 18 | 19 | size_t real_puts(const char *ptr) { 20 | return wa_syscall1(e_puts, (uintptr_t)ptr); 21 | } -------------------------------------------------------------------------------- /src/aligned_alloc.c: -------------------------------------------------------------------------------- 1 | #include "aligned_alloc.h" 2 | #include "_syscalls.h" 3 | 4 | /*int ctz(unsigned int a) { 5 | int c = __builtin_clz(a & -a); 6 | return a ? 31 - c : c; 7 | }*/ 8 | 9 | aligned_ptr x_aligned_alloc(size_t extra, size_t s) { 10 | if(__builtin_clz(extra) + __builtin_ctz(extra) != 31) return (aligned_ptr){ NULL, NULL }; 11 | //if(__builtin_popcount(extra) != 1) return (aligned_ptr){ NULL, NULL }; 12 | void *a = _malloc(s+extra); 13 | void *al = (void *)((((uintptr_t)a) | (extra-1)) + 1); 14 | return (aligned_ptr){ .aligned = al, .raw = a }; 15 | } 16 | 17 | void x_aligned_free(aligned_ptr ptr) { 18 | _free(ptr.raw); 19 | } -------------------------------------------------------------------------------- /src/aligned_alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef ALIGNED_ALLOC_H 2 | #define ALIGNED_ALLOC_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | union { 8 | void *aligned; 9 | void *ptr; 10 | }; 11 | void *raw; 12 | } aligned_ptr; 13 | 14 | aligned_ptr x_aligned_alloc(size_t extra, size_t s); 15 | void x_aligned_free(aligned_ptr ptr); 16 | 17 | #endif -------------------------------------------------------------------------------- /src/c_syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef C_SYSCALL_H 2 | #define C_SYSCALL_H 3 | #include 4 | 5 | static inline uint32_t wa_syscall(uint32_t nr) 6 | { 7 | register uint32_t r0 asm("r0"); 8 | 9 | asm volatile( 10 | "swi %[nr]\n" 11 | : "=r" (r0) 12 | : [nr] "i" (nr) 13 | : "memory", "r1", "r2", "r3", "r4", "r12", "lr"); 14 | 15 | return r0; 16 | } 17 | 18 | static inline uint32_t wa_syscall1(uint32_t nr, uint32_t p1) 19 | { 20 | register uint32_t r0 asm("r0") = p1; 21 | 22 | asm volatile( 23 | "swi %[nr]\n" 24 | : "=r" (r0) 25 | : [nr] "i" (nr), "r" (r0) 26 | : "memory", "r1", "r2", "r3", "r4", "r12", "lr"); 27 | 28 | return r0; 29 | } 30 | 31 | static inline uint32_t wa_syscall2(uint32_t nr, uint32_t p1, uint32_t p2) 32 | { 33 | register uint32_t r0 asm("r0") = p1; 34 | register uint32_t r1 asm("r1") = p2; 35 | 36 | asm volatile( 37 | "swi %[nr]\n" 38 | : "=r" (r0) 39 | : [nr] "i" (nr), "r" (r0), "r" (r1) 40 | : "memory", "r2", "r3", "r4", "r12", "lr"); 41 | 42 | return r0; 43 | } 44 | 45 | static inline uint32_t wa_syscall3(uint32_t nr, uint32_t p1, uint32_t p2, uint32_t p3) 46 | { 47 | register uint32_t r0 asm("r0") = p1; 48 | register uint32_t r1 asm("r1") = p2; 49 | register uint32_t r2 asm("r2") = p3; 50 | 51 | asm volatile( 52 | "swi %[nr]\n" 53 | : "=r" (r0) 54 | : [nr] "i" (nr), "r" (r0), "r" (r1), "r" (r2) 55 | : "memory", "r3", "r4", "r12", "lr"); 56 | 57 | return r0; 58 | } 59 | 60 | static inline uint32_t wa_syscall4(uint32_t nr, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4) 61 | { 62 | register uint32_t r0 asm("r0") = p1; 63 | register uint32_t r1 asm("r1") = p2; 64 | register uint32_t r2 asm("r2") = p3; 65 | register uint32_t r3 asm("r3") = p4; 66 | 67 | asm volatile( 68 | "swi %[nr]\n" 69 | : "=r" (r0) 70 | : [nr] "i" (nr), "r" (r0), "r" (r1), "r" (r2), "r" (r3) 71 | : "memory", "r4", "r12", "lr"); 72 | 73 | return r0; 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /src/calctype.h: -------------------------------------------------------------------------------- 1 | #ifndef CALCTYPE_H 2 | #define CALCTYPE_H 3 | #include 4 | 5 | struct calc_type { 6 | unsigned flash_size; 7 | unsigned i_flash_size; 8 | unsigned boot_page; 9 | unsigned ef_mask; 10 | bool cselcd; 11 | }; 12 | extern struct calc_type g_calc; 13 | 14 | #define FLASH_SIZE g_calc.flash_size 15 | #define BOOT_PAGE g_calc.boot_page 16 | #define EF_MASK g_calc.ef_mask 17 | 18 | #define RAM_SIZE 0x20000 19 | #endif 20 | -------------------------------------------------------------------------------- /src/cselcd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cselcd.h" 3 | #include "cselcd_imp.h" 4 | #include 5 | 6 | uint16_t port_idx = 0; 7 | uint8_t setting_idx = 0; 8 | 9 | uint8_t data_read_lo = 0; 10 | uint8_t reading_data = 0; 11 | uint8_t data_write_hi = 0; 12 | uint8_t writing_data = 0; 13 | 14 | void cselcd_data_set(uint16_t port, uint16_t val); 15 | uint16_t cselcd_data_get(uint16_t port); 16 | 17 | struct cselcd_port cselcd_ports[0xA0]; 18 | 19 | void cselcd_init() { 20 | printf("cselcd_init\n"); 21 | int i; 22 | for(i = 0; i < 0xA0; i++){ 23 | cselcd_ports[i] = (struct cselcd_port){ .pn = i }; 24 | } 25 | cselcd_i_init(); 26 | printf("cselcd_init end\n"); 27 | } 28 | void cselcd_end() { 29 | cselcd_i_end(); 30 | } 31 | void cselcd_ctrl_out(uint8_t val){ 32 | //printf("cselcd_ctrl_out %02x\n", val); 33 | if(setting_idx){ 34 | setting_idx = 0; 35 | port_idx |= val; 36 | }else{ 37 | setting_idx = 1; 38 | port_idx = val << 8; 39 | } 40 | //printf("cselcd_ctrl_out end\n"); 41 | } 42 | 43 | void cselcd_data_out(uint8_t val){ 44 | //printf("cselcd_data_out\n"); 45 | if(writing_data){ 46 | writing_data = 0; 47 | unsigned v = (unsigned)data_write_hi << 8 | (unsigned)val; 48 | cselcd_data_set(port_idx & 0xff, v); 49 | //if(port_idx & 0xff != 0x22) printf("%04x -> p%04x\n", v, port_idx); 50 | }else{ 51 | writing_data = 1; 52 | data_write_hi = val; 53 | } 54 | //printf("cselcd_data_out end\n"); 55 | } 56 | 57 | uint8_t cselcd_data_in(){ 58 | //printf("cselcd_data_in\n"); 59 | if(reading_data) { 60 | reading_data = 0; 61 | return data_read_lo; 62 | }else{ 63 | uint16_t t = cselcd_data_get(port_idx & 0xff); 64 | //if(port_idx & 0xff != 0x22) printf("%04x <- p%04x\n", t, port_idx); 65 | reading_data = 1; 66 | data_read_lo = t & 0xff; 67 | return t >> 8; 68 | } 69 | //printf("cselcd_data_in end\n"); 70 | } 71 | 72 | void cselcd_data_set(uint16_t port, uint16_t val){ 73 | //printf("cselcd_data_set %04x %04x\n", port, val); 74 | struct cselcd_port *p = &cselcd_ports[port]; 75 | p->value = val; 76 | if(p->out) p->out(val); 77 | else if(p->ptr_value) *(p->ptr_value) = val; 78 | } 79 | 80 | uint16_t cselcd_data_get(uint16_t port){ 81 | //printf("cselcd_data_get %04x\n", port); 82 | struct cselcd_port *p = &cselcd_ports[port]; 83 | if(p->in) return p->in(); 84 | if(p->ptr_value) return *(p->ptr_value); 85 | return p->value; 86 | } -------------------------------------------------------------------------------- /src/cselcd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void cselcd_ctrl_out(uint8_t val); 5 | void cselcd_data_out(uint8_t val); 6 | uint8_t cselcd_data_in(); 7 | 8 | void cselcd_init(); 9 | void cselcd_end(); 10 | 11 | struct cselcd_port { 12 | void (*out)(uint16_t val); 13 | uint16_t (*in)(); 14 | uint16_t *ptr_value; 15 | uint16_t pn; 16 | uint16_t value; 17 | }; 18 | 19 | extern struct cselcd_port cselcd_ports[0xA0]; -------------------------------------------------------------------------------- /src/cselcd_imp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cselcd_imp.h" 3 | #include "cselcd.h" 4 | 5 | uint8_t *cse_framebuffer; 6 | uint8_t *cse_bfb; 7 | 8 | typedef uint8_t * byteptr; 9 | uint8_t cselcd_auto_horiz = 1; 10 | uint8_t cselcd_vert_inc = 1; 11 | uint8_t cselcd_horiz_inc = 1; 12 | uint8_t cselcd_bgr = 1; 13 | uint8_t cselcd_tri = 0; 14 | 15 | uint16_t cselcd_pos_x = 0; 16 | uint16_t cselcd_pos_y = 0; 17 | 18 | uint16_t cselcd_s_pos_x = 0; 19 | uint16_t cselcd_s_pos_y = 0; 20 | 21 | uint16_t cselcd_win_ymin = 0x0000; 22 | uint16_t cselcd_win_ymax = 0x00EF; 23 | uint16_t cselcd_win_xmin = 0x0000; 24 | uint16_t cselcd_win_xmax = 0x013F; 25 | 26 | #define LCD_AUTO_HORIZ (1<<3) 27 | #define LCD_VERT_INC (1<<4) 28 | #define LCD_HORIZ_INC (1<<5) 29 | #define LCD_WIN_ORG (1<<7) 30 | #define LCD_BGR (1<<12) 31 | #define LCD_DFM (1<<14) 32 | #define LCD_TRI (1<<15) 33 | 34 | void cselcd_i_data_out(uint16_t val); 35 | uint16_t cselcd_i_data_in(); 36 | void cselcd_entry_out(uint16_t val); 37 | void cselcd_wraparound_x(); 38 | void cselcd_wraparound_y(); 39 | void cselcd_auto_move(); 40 | 41 | void cselcd_set_pos_x(uint16_t v); 42 | void cselcd_set_pos_y(uint16_t v); 43 | 44 | void cselcd_i_init() { 45 | cse_framebuffer = malloc(320 * 240 * 2); 46 | memset(cse_framebuffer, 0x00, 320*240*2); 47 | 48 | *IO_LCD_CONTROL &= (unsigned)~0b100001110; 49 | *IO_LCD_CONTROL |= (unsigned)0b100001100; // 16 bpp 5:6:5, BGR order 50 | 51 | cse_bfb = *(volatile byteptr *)0xC0000010; 52 | *(volatile byteptr *)0xC0000010 = cse_framebuffer; 53 | 54 | cselcd_ports[0x00].value = 0x9335; 55 | cselcd_ports[0x02].value = 0x0200; // LCD Driving Control 56 | cselcd_ports[0x03].value = 0x1038; // Entry Mode 57 | cselcd_ports[0x03].out = cselcd_entry_out; 58 | cselcd_ports[0x07].value = 0x0133; // Display Control 1 59 | cselcd_ports[0x08].value = 0x0202; // Display Control 2 60 | cselcd_ports[0x09].value = 0x0000; // Display Control 3 61 | cselcd_ports[0x0A].value = 0x0000; // Display Control 4 62 | cselcd_ports[0x0C].value = 0x0000; // RGB Display Interface Control 1 63 | cselcd_ports[0x0D].value = 0x0000; // Frame Maker Position 64 | cselcd_ports[0x0F].value = 0x0000; // RGB Display Interface Control 2 65 | cselcd_ports[0x10].value = 0x1190; // Power Control 1 66 | cselcd_ports[0x11].value = 0x0227; // Power Control 2 67 | cselcd_ports[0x12].value = 0x008C; // Power Control 3 68 | cselcd_ports[0x13].value = 0x1800; // Power Control 4 69 | cselcd_ports[0x29].value = 0x0030; // Power Control 7 70 | cselcd_ports[0x2B].value = 0x0000; // Frame Rate and Color Control 71 | cselcd_ports[0x30].value = 0x0000; // Gamma Control 1 72 | cselcd_ports[0x31].value = 0x0305; // Gamma Control 2 73 | cselcd_ports[0x32].value = 0x0002; // Gamma Control 3 74 | cselcd_ports[0x35].value = 0x0301; // Gamma Control 4 75 | cselcd_ports[0x36].value = 0x0004; // Gamma Control 5 76 | cselcd_ports[0x37].value = 0x0507; // Gamma Control 6 77 | cselcd_ports[0x38].value = 0x0204; // Gamma Control 7 78 | cselcd_ports[0x39].value = 0x0707; // Gamma Control 8 79 | cselcd_ports[0x3C].value = 0x0103; // Gamma Control 9 80 | cselcd_ports[0x3D].value = 0x0004; // Gamma Control 10 81 | 82 | cselcd_ports[0x20].ptr_value = &cselcd_s_pos_y; 83 | cselcd_ports[0x21].ptr_value = &cselcd_s_pos_x; 84 | cselcd_ports[0x20].out = &cselcd_set_pos_y; 85 | cselcd_ports[0x21].out = &cselcd_set_pos_x; 86 | 87 | cselcd_ports[0x50].ptr_value = &cselcd_win_ymin; 88 | cselcd_ports[0x51].ptr_value = &cselcd_win_ymax; 89 | cselcd_ports[0x52].ptr_value = &cselcd_win_xmin; 90 | cselcd_ports[0x53].ptr_value = &cselcd_win_xmax; 91 | 92 | cselcd_ports[0x22].out = cselcd_i_data_out; 93 | cselcd_ports[0x22].in = cselcd_i_data_in; 94 | 95 | } 96 | 97 | void cselcd_set_pos_x(uint16_t v) { 98 | cselcd_s_pos_x = v; 99 | cselcd_pos_x = cselcd_s_pos_x; 100 | cselcd_pos_y = cselcd_s_pos_y; 101 | } 102 | 103 | void cselcd_set_pos_y(uint16_t v) { 104 | cselcd_s_pos_y = v; 105 | cselcd_pos_x = cselcd_s_pos_x; 106 | cselcd_pos_y = cselcd_s_pos_y; 107 | } 108 | 109 | void cselcd_i_end(){ 110 | *(volatile byteptr *)0xC0000010 = cse_bfb; 111 | *IO_LCD_CONTROL &= (unsigned)~0b1110; 112 | *IO_LCD_CONTROL |= (unsigned)0b1100; 113 | free(cse_framebuffer); 114 | } 115 | 116 | uint16_t swaprb(uint16_t val){ 117 | return (val & 0b0000011111100000) | (uint16_t)(val >> 11) | (uint16_t)(val << 11); 118 | } 119 | 120 | void cselcd_i_data_out(uint16_t val){ 121 | cse_framebuffer[cselcd_pos_y*320+cselcd_pos_x] = cselcd_bgr ? val : swaprb(val); 122 | cselcd_auto_move(); 123 | } 124 | 125 | uint16_t cselcd_i_data_in(){ 126 | uint16_t v = cse_framebuffer[cselcd_pos_y*320+cselcd_pos_x]; 127 | return cselcd_bgr ? v : swaprb(v); 128 | } 129 | 130 | void cselcd_wraparound_y(){ 131 | if(cselcd_vert_inc){ 132 | if(cselcd_pos_y++ > cselcd_win_ymax){ 133 | cselcd_pos_y = cselcd_win_ymin; 134 | } 135 | }else{ 136 | if(cselcd_pos_y-- < cselcd_win_ymin){ 137 | cselcd_pos_y = cselcd_win_ymax; 138 | } 139 | } 140 | } 141 | 142 | void cselcd_wraparound_x(){ 143 | if(cselcd_horiz_inc){ 144 | if(cselcd_pos_x++ > cselcd_win_xmax){ 145 | cselcd_pos_x = cselcd_win_xmin; 146 | } 147 | }else{ 148 | if(cselcd_pos_x-- < cselcd_win_xmin){ 149 | cselcd_pos_x = cselcd_win_xmax; 150 | } 151 | } 152 | } 153 | 154 | void cselcd_auto_move(){ 155 | if(cselcd_auto_horiz){ 156 | if(cselcd_horiz_inc){ 157 | if(cselcd_pos_x++ > cselcd_win_xmax){ 158 | cselcd_pos_x = cselcd_win_xmin; 159 | cselcd_wraparound_y(); 160 | } 161 | }else{ 162 | if(cselcd_pos_x-- < cselcd_win_xmin){ 163 | cselcd_pos_x = cselcd_win_xmax; 164 | cselcd_wraparound_y(); 165 | } 166 | } 167 | }else{ 168 | if(cselcd_vert_inc){ 169 | if(cselcd_pos_y++ > cselcd_win_ymax){ 170 | cselcd_pos_y = cselcd_win_ymin; 171 | cselcd_wraparound_x(); 172 | } 173 | }else{ 174 | if(cselcd_pos_y-- < cselcd_win_ymin){ 175 | cselcd_pos_y = cselcd_win_ymax; 176 | cselcd_wraparound_x(); 177 | } 178 | } 179 | } 180 | } 181 | 182 | void cselcd_entry_out(uint16_t val){ 183 | cselcd_auto_horiz = (val & LCD_AUTO_HORIZ) && 1; 184 | cselcd_vert_inc = (val & LCD_VERT_INC) && 1; 185 | cselcd_horiz_inc = (val & LCD_HORIZ_INC) && 1; 186 | cselcd_bgr = (val & LCD_BGR) && 1; 187 | cselcd_tri = (val & LCD_TRI) && 1; 188 | } -------------------------------------------------------------------------------- /src/cselcd_imp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cselcd_i_init(); 4 | void cselcd_i_end(); -------------------------------------------------------------------------------- /src/drz80.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DrZ80 Version 1.0 3 | * Z80 Emulator by Reesy 4 | * Copyright 2005 Reesy 5 | * 6 | * This file is part of DrZ80. 7 | * 8 | * DrZ80 is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * DrZ80 is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with DrZ80; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef _DRZ80_H_ 25 | #define _DRZ80_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | extern int DrZ80Ver; // Version number of library 32 | 33 | struct DrZ80 34 | { 35 | unsigned int Z80PC; /*0x00 - PC Program Counter (Memory Base + PC) */ 36 | unsigned int Z80A; /*0x04 - A Register: 0xAA------ */ 37 | unsigned int Z80F; /*0x08 - F Register: 0xFF------ */ 38 | unsigned int Z80BC; /*0x0C - BC Registers: 0xBBCC---- */ 39 | unsigned int Z80DE; /*0x10 - DE Registers: 0xDDEE---- */ 40 | unsigned int Z80HL; /*0x14 - HL Registers: 0xHHLL---- */ 41 | unsigned int Z80SP; /*0x18 - SP Stack Pointer (Memory Base + PC) */ 42 | unsigned int Z80PC_BASE; /*0x1C - PC Program Counter (Memory Base) */ 43 | unsigned int Z80SP_BASE; /*0x20 - SP Stack Pointer (Memory Base) */ 44 | unsigned int Z80IX; /*0x24 - IX Index Register */ 45 | unsigned int Z80IY; /*0x28 - IY Index Register */ 46 | unsigned int Z80I; /*0x2C - I Interrupt Register */ 47 | unsigned int Z80A2; /*0x30 - A' Register: 0xAA------ */ 48 | unsigned int Z80F2; /*0x34 - F' Register: 0xFF------ */ 49 | unsigned int Z80BC2; /*0x38 - B'C' Registers: 0xBBCC---- */ 50 | unsigned int Z80DE2; /*0x3C - D'E' Registers: 0xDDEE---- */ 51 | unsigned int Z80HL2; /*0x40 - H'L' Registers: 0xHHLL---- */ 52 | unsigned char Z80_IRQ; /*0x4C - Set IRQ Number (must be halfword aligned) */ 53 | unsigned char Z80IF; /*0x4D - Interrupt Flags: bit1=_IFF1, bit2=_IFF2, bit3=_HALT */ 54 | unsigned char Z80IM; /*0x4E - Set IRQ Mode */ 55 | unsigned char Z80R; /*0x4F - N/A */ 56 | unsigned int z80irqvector; /*0x50 - Set IRQ Vector i.e. 0xFF=RST */ 57 | void (*z80_irq_callback )(void); 58 | void (*z80_write8 )(unsigned char d,unsigned short a); 59 | void (*z80_write16 )(unsigned short d,unsigned short a); 60 | unsigned char (*z80_in)(unsigned short p); 61 | void (*z80_out )(unsigned short p,unsigned char d); 62 | unsigned char (*z80_read8)(unsigned short a); 63 | unsigned short (*z80_read16)(unsigned short a); 64 | void * (*z80_rebaseSP)(unsigned short new_sp); 65 | void * (*z80_rebasePC)(unsigned short new_pc); 66 | unsigned char Z80_NMI; 67 | void (*z80_trace)(); 68 | }; 69 | 70 | struct DrZ80Regs { 71 | unsigned int Z80PC; /*0x00 - PC Program Counter (Memory Base + PC) */ 72 | unsigned int Z80A; /*0x04 - A Register: 0xAA------ */ 73 | unsigned int Z80F; /*0x08 - F Register: 0xFF------ */ 74 | unsigned int Z80BC; /*0x0C - BC Registers: 0xBBCC---- */ 75 | unsigned int Z80DE; /*0x10 - DE Registers: 0xDDEE---- */ 76 | unsigned int Z80HL; /*0x14 - HL Registers: 0xHHLL---- */ 77 | unsigned int Z80SP; /*0x18 - SP Stack Pointer (Memory Base + PC) */ 78 | unsigned int Z80PC_BASE; /*0x1C - PC Program Counter (Memory Base) */ 79 | unsigned int Z80SP_BASE; /*0x20 - SP Stack Pointer (Memory Base) */ 80 | unsigned int Z80IX; /*0x24 - IX Index Register */ 81 | unsigned int Z80IY; /*0x28 - IY Index Register */ 82 | unsigned int Z80I; /*0x2C - I Interrupt Register */ 83 | unsigned int Z80A2; /*0x30 - A' Register: 0xAA------ */ 84 | unsigned int Z80F2; /*0x34 - F' Register: 0xFF------ */ 85 | unsigned int Z80BC2; /*0x38 - B'C' Registers: 0xBBCC---- */ 86 | unsigned int Z80DE2; /*0x3C - D'E' Registers: 0xDDEE---- */ 87 | unsigned int Z80HL2; /*0x40 - H'L' Registers: 0xHHLL---- */ 88 | unsigned char Z80_IRQ; /*0x4C - Set IRQ Number (must be halfword aligned) */ 89 | unsigned char Z80IF; /*0x4D - Interrupt Flags: bit1=_IFF1, bit2=_IFF2, bit3=_HALT */ 90 | unsigned char Z80IM; /*0x4E - Set IRQ Mode */ 91 | unsigned char Z80R; /*0x4F - N/A */ 92 | unsigned int z80irqvector; /*0x50 - Set IRQ Vector i.e. 0xFF=RST */ 93 | }; 94 | 95 | extern int DrZ80Run(struct DrZ80 *pcy,unsigned int cyc); 96 | 97 | #define Z80_HALT (1<<2) 98 | 99 | #ifdef __cplusplus 100 | } // End of extern "C" 101 | #endif 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/interrupt.c: -------------------------------------------------------------------------------- 1 | #include "interrupt.h" 2 | #include "z_interrupt.h" 3 | #include "speedcontrol.h" 4 | 5 | static void irq_enable(); 6 | static void irq_disable(); 7 | 8 | static void __attribute__((interrupt("IRQ"))) irq_handler(); 9 | 10 | struct keypad { 11 | /*uint8_t scan_mode : 2; 12 | uint16_t apb_row_wait : 14; 13 | uint16_t apb_scan_wait : 16;*/ 14 | uint32_t scan_mode; 15 | /*uint8_t n_rows; 16 | uint8_t n_cols; 17 | uint16_t spacer;*/ 18 | uint32_t n_rows_cols; 19 | uint32_t int_stat; 20 | uint32_t int_mask; 21 | uint16_t kp_data[16]; 22 | uint32_t kp_gpio[4]; 23 | uint32_t tp_int_mask; 24 | uint32_t tp_int_stat; 25 | }; 26 | 27 | struct kp_bkp { 28 | uint32_t int_mask; 29 | uint32_t tp_int_mask; 30 | }; 31 | 32 | uint32_t isr_backup; 33 | uint32_t ei_backup; 34 | struct kp_bkp kp_bkp; 35 | struct keypad volatile *keypad = (struct keypad *)KEYPAD_BASE; 36 | uint32_t *patch_base; 37 | extern volatile uint8_t flag; 38 | 39 | uint32_t pm_int_backup; 40 | 41 | 42 | void interrupt_init(){ 43 | uint32_t swi_addr = *(uint32_t *)0x28; 44 | patch_base = (uint32_t *)(swi_addr + 0xb0); 45 | isr_backup = *ISR_ADDR; 46 | *ISR_ADDR = (uint32_t) irq_handler; 47 | 48 | ei_backup = VIC_REG(0x10); 49 | VIC_REG(0x14) = ~0; // disable all interrupts 50 | VIC_REG(0x10) |= 51 | #ifdef LCD_DOUBLE_BUFFER 52 | 1<<21 | // lcd 53 | #endif 54 | 1<<18 | 1<<16 | 1<<15; // timer 1, keypad, power management 55 | kp_bkp.int_mask = keypad->int_mask; 56 | kp_bkp.tp_int_mask = keypad->tp_int_mask; 57 | keypad->int_mask = 1<<1; 58 | keypad->tp_int_mask = 0; 59 | pm_int_backup = *(volatile uint32_t *)0x900B0010; 60 | *(volatile uint32_t *)0x900B0010 = 1; 61 | patch_ndless_swi(); 62 | uint8_t i = is_classic; 63 | (void)i; 64 | is_touchpad; 65 | irq_enable(); 66 | } 67 | void interrupt_end(){ 68 | irq_disable(); 69 | unpatch_ndless_swi(); 70 | *ISR_ADDR = isr_backup; 71 | *(uint32_t *)0x900B0010 = pm_int_backup; 72 | keypad->int_mask = kp_bkp.int_mask; 73 | keypad->tp_int_mask = kp_bkp.tp_int_mask; 74 | VIC_REG(0x14) = ~0; 75 | VIC_REG(0x10) = ei_backup; 76 | } 77 | 78 | volatile unsigned aaa = 0; 79 | 80 | void __attribute__((interrupt("IRQ"))) irq_handler(){ 81 | uint32_t int_status = VIC_REG(0x00); 82 | if(int_status & 1<<15) { 83 | *(volatile uint32_t *)0x900B0014 = 1; 84 | if(is_on_pressed()) { 85 | //aaa = 1; 86 | int_fire(INT_ON); 87 | } 88 | } 89 | if(int_status & 1<<16) { 90 | keypad->int_stat = 1<<1; 91 | //if(isKeyPressed(KEY_NSPIRE_HOME)){ 92 | //} 93 | } 94 | if(int_status & 1<<18) { 95 | speedcontrol_int(); 96 | } 97 | #ifdef LCD_DOUBLE_BUFFER 98 | if(int_status & 1<<21) { 99 | lcd_int(); 100 | } 101 | #endif 102 | } 103 | 104 | static void irq_enable(){ 105 | unsigned dummy; 106 | __asm__ volatile( 107 | " mrs %0, cpsr\n" 108 | " bic %0, %0, #0x80\n" 109 | " msr cpsr_c, %0\n" : "=r"(dummy) 110 | ); 111 | } 112 | 113 | static void irq_disable(){ 114 | unsigned dummy; 115 | __asm__ volatile( 116 | " mrs %0, cpsr\n" 117 | " orr %0, %0, #0x80\n" 118 | " msr cpsr_c, %0\n" : "=r"(dummy) 119 | ); 120 | } 121 | 122 | uint32_t ndless_swi_bkp[3]; 123 | 124 | void patch_ndless_swi(){ 125 | int i; 126 | for(i = 0; i < 3; i++){ 127 | ndless_swi_bkp[i] = patch_base[i]; 128 | patch_base[i] = 0x00000000; 129 | } 130 | } 131 | void unpatch_ndless_swi(){ 132 | int i; 133 | for(i = 0; i < 3; i++){ 134 | patch_base[i] = ndless_swi_bkp[i]; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/interrupt.h: -------------------------------------------------------------------------------- 1 | #define VIC_BASE 0xDC000000 2 | #define TIMER_BASE 0x900D0000 3 | #define KEYPAD_BASE 0x900E0000 4 | #define _REG(base, x) *((volatile uint32_t *)(base + x)) 5 | #define VIC_REG(x) _REG(VIC_BASE, x) 6 | #define TIMER_REG(x) _REG(TIMER_BASE, x) 7 | #define KEY_REG(x) _REG(KEYPAD_BASE, x) 8 | #define ISR_ADDR ((uint32_t *)0x38) 9 | 10 | void interrupt_init(); 11 | void interrupt_end(); 12 | 13 | void patch_ndless_swi(); 14 | void unpatch_ndless_swi(); 15 | -------------------------------------------------------------------------------- /src/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "calctype.h" 3 | #define STATUS_BATTERIES 1<<0 4 | #define STATUS_LCD_WAIT 1<<1 5 | #define STATUS_FLASH_UNLOCK 1<<2 6 | #define STATUS_HAS_USB 1<<5 7 | #define STATUS_LINK_ASSIST 1<<6 8 | #define STATUS_NOT_83 1<<7 9 | #define STATUS_NORMAL (STATUS_BATTERIES | STATUS_LCD_WAIT | STATUS_HAS_USB |/* STATUS_LINK_ASSIST | */STATUS_NOT_83) 10 | 11 | #include "io.h" 12 | 13 | #include "lcd.h" 14 | #include "cselcd.h" 15 | #include "keypad.h" 16 | #include "mmu_mmap.h" 17 | #include "io_misc.h" 18 | #include "z_interrupt.h" 19 | #include "timer.h" 20 | #include "io.h" 21 | #include "rtc.h" 22 | 23 | #include "util.h" 24 | 25 | struct io_state { 26 | uint8_t mem_size; 27 | uint8_t flash_unlocked; 28 | uint8_t usb_dev_addr; 29 | uint8_t usb_event_mask; 30 | }; 31 | 32 | /*#if CALC_TYPE == CALC_84PCSE 33 | #define I_FLASH_SIZE 2 34 | #else 35 | #define I_FLASH_SIZE 1 36 | #endif*/ 37 | 38 | struct io_state is = {0}; 39 | 40 | struct z80port ports[0x100]; 41 | 42 | void memsize_set(uint8_t val); 43 | void port4_out(uint8_t val); 44 | void usb_set_addr(uint8_t val); 45 | uint8_t status_in(); 46 | 47 | 48 | void io_init(){ 49 | int i; 50 | for(i = 0; i < 0x100; i++){ 51 | ports[i] = (struct z80port){.number = i}; 52 | //ports[i].number = i; 53 | } 54 | is.mem_size = g_calc.i_flash_size | 2<<4; 55 | 56 | ports[0x00].name = "link port"; 57 | ports[0x00].const_val = 0x03; 58 | 59 | ports[0x01].name = "keypad"; 60 | ports[0x01].in.r = keypad_read; 61 | ports[0x01].out.r = keypad_write; 62 | 63 | ports[0x02].name = "status/interrupt ack"; 64 | ports[0x02].in.r = status_in; 65 | ports[0x02].out.r = int_ack_out; 66 | 67 | ports[0x03].name = "interrupt mask"; 68 | ports[0x03].out.r = int_mask_out; 69 | ports[0x03].in.r = int_mask_in; 70 | 71 | ports[0x04].name = "memory map/interrupt"; 72 | ports[0x04].in.r = int_id_in; 73 | ports[0x04].out.r = port4_out; 74 | 75 | ports[0x05].name = "ram page"; 76 | ports[0x06].name = "memory page A"; 77 | ports[0x07].name = "memory page B"; 78 | ports[0x05].out.r = mmu_port5_out; 79 | ports[0x05].in.n = mmap_in; 80 | ports[0x06].out.n = mmu_port67_out; 81 | ports[0x06].in.n = mmap_in; 82 | ports[0x07].mirror = &ports[0x06]; 83 | 84 | ports[0x0E].name = "memory page A high bits"; 85 | ports[0x0F].name = "memory page B high bits"; 86 | ports[0x0E].out.n = mmu_portEF_out; 87 | ports[0x0E].in.n = mmu_portEF_in; 88 | ports[0x0F].mirror = &ports[0x0E]; 89 | 90 | ports[0x10].name = "lcd command"; 91 | #ifdef NO_LCD 92 | ports[0x10].const_val = 0; 93 | #else 94 | if (!g_calc.cselcd) { 95 | ports[0x10].in.r = lcd_cmd_read; 96 | ports[0x10].out.r = lcd_cmd; 97 | } else { 98 | ports[0x10].out.r = cselcd_ctrl_out; 99 | } 100 | #endif 101 | ports[0x12].mirror = &ports[0x10]; 102 | 103 | 104 | ports[0x11].name = "lcd data"; 105 | #ifdef NO_LCD 106 | ports[0x11].const_val = 0; 107 | #else 108 | if (!g_calc.cselcd) { 109 | ports[0x11].in.r = lcd_data_read; 110 | ports[0x11].out.r = lcd_data; 111 | } else { 112 | ports[0x11].in.r = cselcd_data_in; 113 | ports[0x11].out.r = cselcd_data_out; 114 | } 115 | #endif 116 | ports[0x13].mirror = &ports[0x11]; 117 | 118 | ports[0x14].name = "flash unlock"; 119 | ports[0x14].ptr_val = &is.flash_unlocked; // really should be & 1 120 | ports[0x14].const_val = 0; 121 | 122 | ports[0x15].name = "asic version"; 123 | ports[0x15].const_val = 0x45; 124 | 125 | ports[0x20].name = "cpu frequency"; 126 | ports[0x20].in.r = cpu_freq_get; 127 | ports[0x20].out.r = cpu_freq_set; 128 | 129 | ports[0x21].name = "memory size"; 130 | ports[0x21].out.r = memsize_set; 131 | ports[0x21].ptr_val = &is.mem_size; 132 | 133 | ports[0x41].name = "rtc set"; 134 | ports[0x41].out.n = rtc_out; 135 | ports[0x41].in.n = rtc_out_in; 136 | ports[0x42].mirror = 137 | ports[0x43].mirror = 138 | ports[0x44].mirror = &ports[0x41]; 139 | 140 | ports[0x45].name = "rtc get"; 141 | ports[0x45].in.n = rtc_in; 142 | ports[0x46].mirror = 143 | ports[0x47].mirror = 144 | ports[0x48].mirror = &ports[0x45]; 145 | 146 | ports[0x4c].name = "usb status"; 147 | ports[0x4c].const_val = 0x22; // usb stuff 148 | 149 | ports[0x4d].name = "usb line status"; 150 | ports[0x4d].const_val = 0b10100101; // usb stuff 151 | ports[0x4d].out.r = NULL; // explicitly does nothing 152 | 153 | ports[0x55].name = "usb interrupts"; 154 | ports[0x55].const_val = 0x1f; // usb interrupts 155 | 156 | ports[0x56].name = "usb line events"; 157 | ports[0x56].const_val = 0; // individual usb interrupts 158 | 159 | ports[0x57].name = "usb event mask"; 160 | ports[0x57].ptr_val = &is.usb_event_mask; 161 | 162 | ports[0x80].name = "usb address"; 163 | ports[0x80].out.r = usb_set_addr; 164 | ports[0x80].ptr_val = &is.usb_dev_addr; 165 | } 166 | 167 | void memsize_set(uint8_t val){ 168 | is.mem_size = val & 0b00110011; 169 | } 170 | 171 | void port4_out(uint8_t val){ 172 | mmap_set_mode(val & 0x01); 173 | timer_freq_set((val >> 1) & 0b11); 174 | } 175 | 176 | void usb_set_addr(uint8_t val){ 177 | is.usb_dev_addr = val & 0x7f; 178 | } 179 | 180 | uint8_t status_in(){ 181 | return STATUS_NORMAL | is.flash_unlocked<<2; 182 | } 183 | 184 | void io_save(FILE *f){ 185 | FWRITE_VALUE(is, f); 186 | } 187 | 188 | void io_restore(FILE *f){ 189 | FREAD_VALUE(&is, f); 190 | } 191 | -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #pragma once 4 | struct z80port { 5 | uint8_t number; 6 | struct z80port *mirror; 7 | union { 8 | void (*r)(uint8_t val); 9 | void (*n)(uint8_t val, uint8_t port); 10 | } out; 11 | 12 | union { 13 | uint8_t (*r)(); 14 | uint8_t (*n)(uint8_t port); 15 | } in; 16 | 17 | uint8_t *ptr_val; 18 | uint8_t const_val; 19 | 20 | const char *name; 21 | }; 22 | 23 | extern struct z80port ports[0x100]; 24 | void io_init(); 25 | 26 | void io_save(FILE *f); 27 | void io_restore(FILE *f); -------------------------------------------------------------------------------- /src/io_misc.h: -------------------------------------------------------------------------------- 1 | uint8_t default_in(uint8_t port); 2 | void default_out(uint8_t port, uint8_t val); -------------------------------------------------------------------------------- /src/keypad.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "keypad.h" 3 | #define K(x) &(KEY_NSPIRE_##x) 4 | #define J(x) &(KEY_84_##x) 5 | #define KEY_TABLE n_key_ar 6 | uint8_t mon = 0; 7 | 8 | const t_key *n_legacy_key_ar[8][7] = { 9 | {K(DOWN), K(ENTER), K(NEGATIVE), K(PERIOD), K(0), NULL, K(EQU)}, 10 | {K(LEFT), K(PLUS), K(3), K(2), K(1), K(FLAG), K(TRIG)}, 11 | {K(RIGHT), K(MINUS), K(6), K(5), K(4), K(eEXP), K(EE)}, 12 | {K(UP), K(MULTIPLY), K(9), K(8), K(7), K(TENX), K(FRAC)}, 13 | {NULL, K(DIVIDE), K(RP), K(LP), K(COMMA),K(SQU), K(A)}, 14 | {NULL, K(EXP), K(TAN), K(COS), K(SIN), K(QUESEXCL), K(CTRL)}, 15 | {NULL, K(RET), K(VAR), K(SCRATCHPAD), K(DOC), K(MENU), K(TAB)}, 16 | {NULL, NULL, NULL, K(PI), K(X), K(SHIFT), K(DEL)} 17 | }; 18 | 19 | const t_key *n_key_ar[8][7] = { 20 | {K(DOWN), K(ENTER), K(NEGATIVE), K(PERIOD), K(0), NULL, K(CAT)}, 21 | {K(LEFT), K(PLUS), K(3), K(2), K(1), K(FLAG), K(FRAC)}, 22 | {K(RIGHT), K(MINUS), K(6), K(5), K(4), K(eEXP), K(EE)}, 23 | {K(UP), K(MULTIPLY), K(9), K(8), K(7), K(TENX), K(TRIG)}, 24 | {NULL, K(DIVIDE), K(RP), K(LP), K(COMMA),K(SQU), K(EQU)}, 25 | {NULL, K(EXP), K(TAN), K(F), K(E), K(QUESEXCL), K(CTRL)}, 26 | {NULL, K(RET), K(VAR), K(SCRATCHPAD), K(DOC), K(MENU), K(TAB)}, 27 | {NULL, NULL, NULL, K(PI), K(X), K(SHIFT), K(DEL)} 28 | }; 29 | 30 | const t_key *n_84_key_ar[8][7] = { 31 | {J(DOWN), J(ENTER), J(NEGATIVE), J(PERIOD), J(0), NULL, J(GRAPH)}, 32 | {J(LEFT), J(PLUS), J(3), J(2), J(1), J(STO), J(TRACE)}, 33 | {J(RIGHT), J(MINUS), J(6), J(5), J(4), J(LN), J(ZOOM)}, 34 | {J(UP), J(MULTIPLY), J(9), J(8), J(7), J(LOG), J(WIND)}, 35 | {NULL, J(DIVIDE), J(RP), J(LP), J(COMMA),J(SQU), J(YEQU)}, 36 | {NULL, J(EXP), J(TAN), J(COS), J(SIN), J(INV), J(2ND)}, 37 | {NULL, J(CLEAR), J(VARS), J(PRGM), J(APPS),J(MATH), J(MODE)}, 38 | {NULL, NULL, NULL, J(STAT), J(X), J(ALPHA), J(DEL)} 39 | }; 40 | 41 | const t_key* (*key_ar[])[7] = { 42 | n_key_ar, 43 | n_84_key_ar, 44 | n_legacy_key_ar 45 | }; 46 | 47 | static enum z80_keypad_type key_type = 0; 48 | 49 | void keypad_set_type(enum z80_keypad_type val) { 50 | key_type = val; 51 | } 52 | 53 | void keypad_write(uint8_t val){ 54 | //printf("keypad_write %02x\n", val); 55 | mon = ~val; 56 | } 57 | 58 | uint8_t keypad_read(){ 59 | const t_key * const(* c_key_ar)[7] = key_ar[(int)key_type]; 60 | int i; 61 | uint8_t o = 0; 62 | for(i = 0; i < 7; i++){ 63 | if(mon & 1< 2 | #include "lcd.h" 3 | #include "util.h" 4 | #include "_syscalls.h" 5 | #include "mmu_mmap.h" 6 | #include "aligned_alloc.h" 7 | 8 | struct lcd_state { 9 | int cur_row; 10 | int cur_col; 11 | unsigned flags; 12 | int n_bits; 13 | uint8_t auto_mode; 14 | uint8_t enabled; 15 | uint8_t lcd_read_reg; 16 | uint8_t contrast; 17 | }; 18 | 19 | /*struct lcd_state_ex { 20 | struct lcd_state; 21 | union { 22 | unsigned _ex_start; 23 | int row_offset; 24 | }; 25 | };*/ 26 | 27 | static const unsigned char power_btn[20][3] = { 28 | {0x00,0x60,0x00}, 29 | {0x00,0x60,0x00}, 30 | {0x00,0x60,0x00}, 31 | {0x06,0x66,0x00}, 32 | {0x0e,0x67,0x00}, 33 | {0x1c,0x63,0x80}, 34 | {0x38,0x61,0xc0}, 35 | {0x30,0x60,0xc0}, 36 | {0x60,0x00,0x60}, 37 | {0x60,0x00,0x60}, 38 | {0x60,0x00,0x60}, 39 | {0x60,0x00,0x60}, 40 | {0x60,0x00,0x60}, 41 | {0x60,0x00,0x60}, 42 | {0x30,0x00,0xc0}, 43 | {0x38,0x01,0xc0}, 44 | {0x1c,0x03,0x80}, 45 | {0x0e,0x07,0x00}, 46 | {0x07,0xfe,0x00}, 47 | {0x01,0xf8,0x00} 48 | }; 49 | 50 | struct lcd_state ls = { 0, 0, 1, 8, AUTO_DOWN, TRUE, 0, 0 }; 51 | //uint8_t video_mem[120*64/8]; 52 | 53 | void *os_framebuffer; 54 | struct buf_p { 55 | uint8_t *phys; 56 | uint8_t *virt; 57 | }; 58 | 59 | struct buf_p back_buffer; 60 | aligned_ptr framebuffer_a; 61 | #ifdef LCD_DOUBLE_BUFFER 62 | struct buf_p front_buffer; 63 | aligned_ptr framebuffer_b; 64 | #endif 65 | static uint32_t * const palette = (uint32_t *)0xC0000200; 66 | static volatile unsigned * lcd_control; 67 | static unsigned is_hww = 0; 68 | static unsigned xy_to_fbo(unsigned x, unsigned y){ 69 | if(is_hww) { 70 | return x * 240 + y; 71 | } else { 72 | return y * 320 + x; 73 | } 74 | } 75 | 76 | //#define XY_TO_IDX(x, y) ((y) * 120 + (x)) 77 | //#define XY_TO_FBO(x, y) ((y) * 320 + (x)) 78 | #define MAX_COL ((ls.n_bits == 8) ? 14 : 19) 79 | #define C_XO ((320-(96*3))/2) 80 | #define C_YO ((240-(64*3))/2) 81 | 82 | //#define C_OFFSET XY_TO_FBO(C_XO, C_YO) 83 | 84 | unsigned c_offset; 85 | 86 | typedef uint8_t * byteptr; 87 | 88 | //#define FB_OFFSET(x, y) (((y) * 320 + (x)) >> 1) 89 | //#define printf(...) 90 | 91 | #ifdef LCD_DOUBLE_BUFFER 92 | static void swap_buffers(); 93 | static uint32_t b_int; 94 | #endif 95 | 96 | static uint16_t pack_rgb(uint8_t r, uint8_t g, uint8_t b){ 97 | return b >> 3 | g >> 3 << 5 | r >> 3 << 10; 98 | } 99 | 100 | static uint16_t pack_rgbp(uint32_t rgb){ 101 | return pack_rgb(rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff); 102 | } 103 | static uint16_t pack_gry(uint8_t v) { 104 | uint8_t z = (v & 4) >> 2; 105 | v >>= 3; 106 | return v | (v << 5) | (v << 10) | (z << 15); 107 | } 108 | 109 | typedef void (*n_set_84_pixel_t)(int x, int y, uint8_t gray, uint8_t *fb_a); 110 | 111 | void _n_set_84_pixel(int x, int y, uint8_t gray, uint8_t *fb_a); 112 | void _n_set_84_pixel_hww(int x, int y, uint8_t gray, uint8_t *fb_a); 113 | 114 | n_set_84_pixel_t correct_setpixel; 115 | 116 | #ifdef LCD_DOUBLE_BUFFER 117 | struct pixel_write { 118 | uint8_t x; 119 | uint8_t y : 7; 120 | uint8_t v : 1; 121 | }; 122 | 123 | struct pixel_write write_buffer[1024]; 124 | unsigned write_idx = 0; 125 | unsigned wr_overflow = 0; 126 | #endif 127 | 128 | static void fb_setup(uint8_t *buf) { 129 | int x, y, i = 0; 130 | if(is_hww) { 131 | for(y = 0; y < 320; y++) { 132 | for(x = 0; x < 240; x++) { 133 | if(y >= C_XO && y < (320 - C_XO) && x == C_YO) { 134 | memset(buf+i, 0, 64*3); 135 | i += 64*3; 136 | x += 64*3; 137 | } 138 | buf[i++] = ((x & 1) ^ (y & 1)) + 4 + 139 | ( 140 | (x >= 2 && x < 22 && y >= C_XO && y < (C_XO+20) && 141 | (power_btn[x-2][(y-C_XO) >> 3] & 1<<(7-((y-C_XO)&7)))) ? 2 : 0 142 | ); 143 | } 144 | } 145 | } else { 146 | for(y = 0; y < 240; y++) { 147 | for(x = 0; x < 320; x++) { 148 | if(y >= C_YO && y < (240 - C_YO) && x == C_XO) { 149 | memset(buf+i, 0, 96*3); 150 | i += 96*3; 151 | x += 96*3; 152 | } 153 | buf[i++] = ((x & 1) ^ (y & 1)) + 4 + 154 | ( 155 | (y >= 2 && y < 22 && x >= C_XO && x < (C_XO+20) && 156 | (power_btn[y-2][(x-C_XO) >> 3] & 1<<(7-((x-C_XO)&7)))) ? 2 : 0 157 | ); 158 | } 159 | } 160 | } 161 | } 162 | 163 | static uint32_t b_lcd_control; 164 | 165 | void m_lcd_init(){ 166 | is_hww = nl_ndless_rev() >= 2004 && _lcd_type() == SCR_240x320_565; 167 | printf("is_hww=%d\n", is_hww); 168 | lcd_control = IO_LCD_CONTROL; 169 | 170 | 171 | framebuffer_a = x_aligned_alloc(0x1000, FB_SIZE); 172 | map_framebuffer(framebuffer_a.ptr); 173 | //framebuffer_b = x_aligned_alloc(8, 320*240); 174 | #ifdef LCD_DOUBLE_BUFFER 175 | front_buffer = (struct buf_p){framebuffer_a.ptr, (uint8_t *)0xe0050000}; 176 | back_buffer = (struct buf_p){((uint8_t *)front_buffer.phys) + 320*240, (uint8_t *)0xe0050000 + 320*240}; 177 | fb_setup(front_buffer.virt); 178 | #else 179 | back_buffer = (struct buf_p){framebuffer_a.ptr, (uint8_t *)0xe0050000}; 180 | #endif 181 | 182 | fb_setup(back_buffer.virt); 183 | 184 | //front_buffer[0] = front_buffer[1] = front_buffer[320] = front_buffer[321] = 2; 185 | //back_buffer[318] = back_buffer[319] = back_buffer[320+318] = back_buffer[320+319] = 2; 186 | //lcd_ingray(); 187 | //memset(framebuffer, 0xff, 320*240); 188 | 189 | b_lcd_control = *lcd_control; 190 | *lcd_control = (*lcd_control & ~0b1110) | 0b0110; // 8 bpp, palette. 191 | #ifdef LCD_DOUBLE_BUFFER 192 | *lcd_control = (*lcd_control & ~(0b11 << 12)) | (0b00 << 12); // Interrupt on VSync 193 | b_int = *(uint32_t *)0xc000001c; 194 | *(uint32_t *)0xc000001c = 1<<3; // v compare interrupt 195 | #endif 196 | 197 | os_framebuffer = REAL_SCREEN_BASE_ADDRESS; 198 | #ifdef LCD_DOUBLE_BUFFER 199 | REAL_SCREEN_BASE_ADDRESS = front_buffer.phys; 200 | #else 201 | REAL_SCREEN_BASE_ADDRESS = back_buffer.phys; 202 | #endif 203 | 204 | c_offset = xy_to_fbo(C_XO, C_YO); 205 | correct_setpixel = is_hww ? _n_set_84_pixel_hww : _n_set_84_pixel; 206 | 207 | palette[0] = pack_gry(0xff); 208 | palette[1] = pack_rgbp(0xff0000) * 0x10001; 209 | palette[2] = 0xffff0000; 210 | palette[3] = palette[2]; 211 | } 212 | 213 | void lcd_end(){ 214 | #ifdef LCD_DOUBLE_BUFFER 215 | *(uint32_t *)0xc000001c = b_int; 216 | #endif 217 | REAL_SCREEN_BASE_ADDRESS = os_framebuffer; 218 | *lcd_control = b_lcd_control; 219 | x_aligned_free(framebuffer_a); 220 | //x_aligned_free(framebuffer_b); 221 | } 222 | 223 | __attribute__((naked)) void _n_set_84_pixel(int x, int y, uint8_t gray, uint8_t *fb_a) { 224 | (void)x; 225 | (void)y; 226 | (void)gray; 227 | (void)fb_a; 228 | asm( 229 | " add r1, r1, r1, lsl #2\n" 230 | " add r0, r0, r1, lsl #6\n" 231 | " add r0, r0, r0, lsl #1\n" 232 | " add r0, r3\n" 233 | " mov r1, #3\n" 234 | "1: subs r1, #1\n" 235 | " strb r2, [r0, #0]\n" 236 | " strb r2, [r0, #1]\n" 237 | " strb r2, [r0, #2]\n" 238 | " add r0, #320\n" 239 | " bne 1b\n" 240 | " bx lr\n" 241 | ); 242 | } 243 | 244 | /*void _n_set_84_pixel(int x, int y, uint8_t gray, uint8_t * fb_a) { 245 | x += y * 320; 246 | fb_a += x * 3; 247 | for(y = 3; y; y--) { 248 | fb_a[0] = gray; 249 | fb_a[1] = gray; 250 | fb_a[2] = gray; 251 | fb_a += 320; 252 | } 253 | }*/ 254 | 255 | __attribute__((naked)) void _n_set_84_pixel_hww(int x, int y, uint8_t gray, uint8_t *fb_a) { 256 | (void)x; 257 | (void)y; 258 | (void)gray; 259 | (void)fb_a; 260 | asm( 261 | " rsb r0, r0, r0, lsl #4\n" 262 | " add r0, r1, r0, lsl #4\n" 263 | " add r0, r0, r0, lsl #1\n" 264 | " add r0, r3\n" 265 | " mov r1, #3\n" 266 | "1: subs r1, #1\n" 267 | " strb r2, [r0, #0]\n" 268 | " strb r2, [r0, #1]\n" 269 | " strb r2, [r0, #2]\n" 270 | " add r0, #240\n" 271 | " bne 1b\n" 272 | " bx lr\n" 273 | ); 274 | } 275 | 276 | /*void _n_set_84_pixel_hww(int x, int y, uint8_t gray, uint8_t * fb_a) { 277 | y += x * 240; 278 | fb_a += y * 3; 279 | for(x = 3; x; x--) { 280 | fb_a[0] = gray; 281 | fb_a[1] = gray; 282 | fb_a[2] = gray; 283 | fb_a += 240; 284 | } 285 | }*/ 286 | 287 | 288 | static uint8_t extra_screen[64][(120-96)/8]; 289 | 290 | static void n_set_84_pixel(int x, int y, uint8_t gray, uint8_t *buf){ 291 | correct_setpixel(x, y, gray, buf + c_offset); 292 | } 293 | 294 | static uint8_t get_pixel(int x, int y){ 295 | //printf("gp %d %d %d %d\n", x, y, c_offset, xy_to_fbo(x*3,y*3)); 296 | if(x >= 96) { 297 | return (extra_screen[y][(x-96)/8] >> (x&7)) & 1; 298 | } 299 | return back_buffer.virt[c_offset + xy_to_fbo(x*3, y*3)] && 1; 300 | } 301 | 302 | static void set_pixel(int x, int y, uint8_t val, uint8_t *buf){ 303 | //printf("set_pixel %d %d %d\n", x, y, val); 304 | if(y >= 64) return; 305 | if(x >= 96) { 306 | uint8_t *c = &extra_screen[y][(x-96)/8]; 307 | if(val) 308 | *c |= (1<<(x&7)); 309 | else 310 | *c &= ~(1<<(x&7)); 311 | } else { 312 | unsigned vv = val ? 1 : 0; 313 | if(get_pixel(x, y) == vv) return; 314 | n_set_84_pixel(x, y, vv, buf); 315 | #ifdef LCD_DOUBLE_BUFFER 316 | if(write_idx == sizeof(write_buffer) / sizeof(write_buffer[0])) { 317 | wr_overflow = 1; 318 | return; 319 | } 320 | write_buffer[write_idx++] = (struct pixel_write){ .x = x, .y = y, .v = vv }; 321 | #endif 322 | } 323 | } 324 | 325 | #ifdef LCD_DOUBLE_BUFFER 326 | void lcd_int() { 327 | *(uint32_t *)0xc0000028 = 1<<3; // acknowledge interrupt; 328 | swap_buffers(); 329 | } 330 | 331 | static void swap_buffers() { 332 | struct buf_p a = back_buffer; 333 | back_buffer = front_buffer; 334 | front_buffer = a; 335 | REAL_SCREEN_BASE_ADDRESS = front_buffer.phys; 336 | if(wr_overflow) { 337 | memcpy(back_buffer.virt, front_buffer.virt, 320*240); 338 | wr_overflow = 0; 339 | } else { 340 | int i; 341 | for(i = 0; i < write_idx; i++) { 342 | struct pixel_write w = write_buffer[i]; 343 | n_set_84_pixel(w.x, w.y, w.v, back_buffer.virt); 344 | } 345 | } 346 | write_idx = 0; 347 | } 348 | #endif 349 | 350 | 351 | void set_contrast(uint8_t contrast){ 352 | //printf("set_contrast %d\n", set_contrast); 353 | int black = contrast * 2; 354 | int white = 0xff - contrast * 2; 355 | palette[0] = (pack_gry(black) << 16) | pack_gry(white); 356 | //printf("%d %d %d %08x\n", contrast, black, white, palette[0]); 357 | ls.contrast = contrast; 358 | } 359 | 360 | void lcd_cmd(uint8_t cmd){ 361 | if(cmd >= 0x20 && cmd <= 0x3F){ 362 | ls.cur_col = cmd - 0x20; 363 | //printf("col %d\n", ls.cur_col); 364 | return; 365 | } 366 | if(cmd >= 0x80 && cmd <= 0xBF){ 367 | ls.cur_row = cmd - 0x80; 368 | //printf("row %d\n", ls.cur_row); 369 | } 370 | if(cmd >= 0xC0){ 371 | set_contrast(0xff - cmd); 372 | // contrast 373 | return; 374 | } 375 | switch(cmd){ 376 | case BIT_6: 377 | ls.n_bits = 6; 378 | //printf("6 bit mode\n"); 379 | break; 380 | case BIT_8: 381 | ls.n_bits = 8; 382 | //printf("8 bit mode\n"); 383 | //printf("%d bits\n", ls.n_bits); 384 | break; 385 | case LCD_ENABLE: 386 | ls.enabled = TRUE; 387 | palette[3] = palette[2]; 388 | //set_contrast(ls.contrast); 389 | //puts("ls.enabled"); 390 | break; 391 | case LCD_DISABLE: 392 | ls.enabled = FALSE; 393 | //palette[3] = pack 394 | palette[3] = pack_rgbp(0x7f0000) * 0x10001; 395 | //puts("disabled"); 396 | break; 397 | case AUTO_UP: 398 | case AUTO_DOWN: 399 | case AUTO_LEFT: 400 | case AUTO_RIGHT: 401 | //printf("auto %d\n", cmd); 402 | ls.auto_mode = cmd; 403 | break; 404 | } 405 | } 406 | 407 | uint8_t lcd_cmd_read(){ 408 | uint8_t v = (ls.auto_mode == AUTO_RIGHT || ls.auto_mode == AUTO_DOWN); 409 | v |= (ls.auto_mode == AUTO_LEFT || ls.auto_mode == AUTO_RIGHT) << 1; 410 | v |= ls.enabled << 5; 411 | v |= (ls.n_bits == 8) << 6; 412 | return v; 413 | } 414 | 415 | void lcd_auto_move(){ 416 | switch(ls.auto_mode){ 417 | case AUTO_UP: 418 | ls.cur_row = (ls.cur_row - 1) & 63; 419 | break; 420 | case AUTO_DOWN: 421 | ls.cur_row = (ls.cur_row + 1) & 63; 422 | break; 423 | case AUTO_LEFT: 424 | ls.cur_col--; 425 | if(ls.cur_col == -1) ls.cur_col = MAX_COL; 426 | break; 427 | case AUTO_RIGHT: 428 | ls.cur_col++; 429 | if(ls.cur_col == MAX_COL + 1) ls.cur_col = 0; 430 | if(ls.cur_col == 32) ls.cur_col = 0; 431 | break; 432 | } 433 | 434 | } 435 | 436 | #ifdef LCD_DOUBLE_BUFFER 437 | static void irq_enable(){ 438 | unsigned dummy; 439 | __asm__ volatile( 440 | " mrs %0, cpsr\n" 441 | " bic %0, %0, #0x80\n" 442 | " msr cpsr_c, %0\n" : "+r"(dummy) 443 | ); 444 | } 445 | 446 | static void irq_disable(){ 447 | unsigned dummy; 448 | __asm__ volatile( 449 | " mrs %0, cpsr\n" 450 | " orr %0, %0, #0x80\n" 451 | " msr cpsr_c, %0\n" : "+r"(dummy) 452 | ); 453 | } 454 | #endif 455 | 456 | void lcd_data(uint8_t data){ 457 | int i; 458 | int x = ls.cur_col * ls.n_bits; 459 | int y = ls.cur_row; 460 | #ifdef LCD_DOUBLE_BUFFER 461 | irq_disable(); 462 | #endif 463 | for(i = 0; i < ls.n_bits; i++){ 464 | set_pixel(x + i, y, data & (1<<(ls.n_bits-1-i)), back_buffer.virt); 465 | } 466 | #ifdef LCD_DOUBLE_BUFFER 467 | irq_enable(); 468 | #endif 469 | lcd_auto_move(); 470 | /*if(data && !isKeyPressed(KEY_84_ALPHA)){ 471 | while(!isKeyPressed(KEY_84_2ND)); 472 | while(isKeyPressed(KEY_84_2ND)); 473 | }*/ 474 | } 475 | 476 | uint8_t lcd_read_reg = 0; 477 | 478 | uint8_t _lcd_data_read(){ 479 | int x = ls.cur_col * ls.n_bits; 480 | int y = ls.cur_row; 481 | int i; 482 | uint8_t v = 0; 483 | for(i = 0; i < ls.n_bits; i++){ 484 | v <<= 1; 485 | v |= get_pixel(x + i, y); 486 | } 487 | lcd_auto_move(); 488 | //t <<= (8 - ls.n_bits); 489 | //if(ls.n_bits == 8) ls.cur_row++;//lcd_auto_move(); 490 | //if(t) printf("hi\n"); 491 | return v; 492 | } 493 | 494 | uint8_t lcd_data_read() { 495 | uint8_t v = ls.lcd_read_reg; 496 | ls.lcd_read_reg = _lcd_data_read(); 497 | return v; 498 | } 499 | 500 | void lcd_save(FILE *f){ 501 | ls.flags |= 1; 502 | FWRITE_VALUE(ls, f); 503 | FWRITE_VALUE(extra_screen, f); 504 | 505 | int y; 506 | int j = 0; 507 | uint8_t *b = malloc(768); 508 | for(y = 0; y < 64; y++) { 509 | int x; 510 | for(x = 0; x < 96;) { 511 | int i; 512 | uint8_t v = 0; 513 | for(i = 0; i < 8; i++, x++) { 514 | v <<= 1; 515 | v |= get_pixel(x, y); 516 | } 517 | b[j++] = v; 518 | } 519 | } 520 | fwrite(b, 768, 1, f); 521 | free(b); 522 | } 523 | 524 | void lcd_restore(FILE *f){ 525 | FREAD_VALUE(&ls, f); 526 | if(ls.flags & 1) { 527 | // fread(&ls._ex_start, sizeof(struct lcd_state_ex)-sizeof(struct lcd_state), 1, f); 528 | FREAD_VALUE(&extra_screen, f); 529 | } 530 | 531 | uint8_t *b = malloc(768); 532 | fread(b, 768, 1, f); 533 | uint8_t *p = b; 534 | int y; 535 | for(y = 0; y < 64; y++){ 536 | int x; 537 | for(x = 0; x < 96;){ 538 | int i; 539 | uint8_t d = *p++; 540 | for(i = 0; i < 8; i++, x++) { 541 | set_pixel(x, y, d >> 7, back_buffer.virt); 542 | d <<= 1; 543 | } 544 | } 545 | } 546 | 547 | free(b); 548 | 549 | set_contrast(ls.contrast); 550 | } 551 | -------------------------------------------------------------------------------- /src/lcd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | void m_lcd_init(); 6 | void lcd_end(); 7 | void lcd_cmd(uint8_t); 8 | void lcd_data(uint8_t); 9 | uint8_t lcd_cmd_read(); 10 | uint8_t lcd_data_read(); 11 | 12 | void lcd_save(FILE *f); 13 | void lcd_restore(FILE *f); 14 | 15 | #ifdef LCD_DOUBLE_BUFFER 16 | #define FB_SIZE (320*240*2) 17 | #else 18 | #define FB_SIZE (320*240) 19 | #endif 20 | 21 | #define BIT_6 0 22 | #define BIT_8 1 23 | #define LCD_DISABLE 2 24 | #define LCD_ENABLE 3 25 | #define AUTO_UP 4 26 | #define AUTO_DOWN 5 27 | #define AUTO_LEFT 6 28 | #define AUTO_RIGHT 7 -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "drz80.h" 4 | #include "interrupt.h" 5 | #include "z_interrupt.h" 6 | #include "io.h" 7 | #include "mmu_mmap.h" 8 | #include "lcd.h" 9 | #include "timer.h" 10 | #include "speedcontrol.h" 11 | #include "savestate.h" 12 | #include "rtc.h" 13 | #include "keypad.h" 14 | #include "main.h" 15 | #include "cselcd.h" 16 | #include 17 | #include 18 | #include "navnet-io.h" 19 | 20 | #include "keys.h" 21 | 22 | void cpu_init(); 23 | void * cpu_rebaseSP(uint16_t x); 24 | unsigned short cpu_read16(uint16_t idx); 25 | unsigned char cpu_read8(uint16_t idx); 26 | void cpu_write16(unsigned short val, uint16_t idx); 27 | void cpu_write8(unsigned char val, uint16_t idx); 28 | unsigned char cpu_in(unsigned short port); 29 | //static unsigned char cpu_in_(unsigned short port); 30 | void cpu_out(unsigned short port, unsigned char val); 31 | void cpu_irq_callback(); 32 | 33 | uint8_t port_get(uint8_t pn, struct z80port *p); 34 | void port_set(uint8_t pn, struct z80port *p, uint8_t val); 35 | 36 | #ifdef USE_NAVNETIO 37 | 38 | nn_stream g_stream; 39 | 40 | size_t __wrap_printf(const char *format, ...) { 41 | va_list args; 42 | va_start(args, format); 43 | size_t z; 44 | if(g_stream == NULL) { 45 | z = vprintf(format, args); 46 | } else { 47 | //vprintf(format, args); 48 | z = navnet_io_vprintf(g_stream, format, args); 49 | } 50 | va_end(args); 51 | return z; 52 | } 53 | 54 | size_t __wrap_puts(const char *str) { 55 | return printf("%s\n", str); 56 | } 57 | 58 | #endif 59 | //#define printf(...) 60 | 61 | const struct calc_type calc_types[] = { 62 | { // 84+SE 63 | .flash_size = 0x200000, 64 | .i_flash_size = 1, 65 | .boot_page = 0x7f, 66 | .ef_mask = 0, 67 | .cselcd = 0 68 | }, 69 | { // 84+ 70 | .flash_size = 0x100000, 71 | .i_flash_size = 0, 72 | .boot_page = 0x3f, 73 | .ef_mask = 0, 74 | .cselcd = 0 75 | }, 76 | { // 84+CSE 77 | .flash_size = 0x400000, 78 | .i_flash_size = 2, 79 | .boot_page = 0xff, 80 | .ef_mask = 1, 81 | .cselcd = 1 82 | } 83 | }; 84 | 85 | struct calc_type g_calc = calc_types[0]; 86 | #define N_CALC_TYPES (sizeof(calc_types) / sizeof(calc_types[0])) 87 | 88 | 89 | //uint8_t *flash; 90 | struct DrZ80 ZCpu; 91 | uint32_t port_debug = 0; 92 | //volatile extern unsigned aaa; 93 | 94 | int main(int argc, char **argv){ 95 | if(argc == 1){ 96 | //*dot = '\0'; 97 | cfg_register_fileext("8rom", "nspire-z80"); 98 | cfg_register_fileext("8sav", "nspire-z80"); 99 | //*dot = '.'; 100 | show_msgbox("Info", "File extension registered. Open a 8rom file to use."); 101 | return 0; 102 | } 103 | #ifdef USE_NAVNETIO 104 | navnet_io_early(); 105 | g_stream = navnet_io_init(); 106 | #endif 107 | printf("main = %p\n", main); 108 | enable_relative_paths(argv); 109 | keypad_set_type(KEYPAD_NSPIRE); 110 | FILE *cfg_file = fopen("nspire-z80.cfg.tns", "r"); 111 | if(cfg_file) { 112 | puts("Reading config file..."); 113 | fseek(cfg_file, 0, SEEK_END); 114 | int cfg_size = ftell(cfg_file); 115 | fseek(cfg_file, 0, 0); 116 | char *cfg = malloc(cfg_size + 1); 117 | fread(cfg, 1, cfg_size, cfg_file); 118 | cfg[cfg_size] = 0; 119 | fclose(cfg_file); 120 | char *cur_cfg = cfg; 121 | puts(cfg); 122 | #define L_STRNCMP(a, b) strncmp(a, b, strlen(b)) 123 | while(cur_cfg < cfg + cfg_size) { 124 | if(L_STRNCMP(cur_cfg, "keypad=") == 0) { 125 | puts("bbb"); 126 | cur_cfg += strlen("keypad="); 127 | if(L_STRNCMP(cur_cfg, "84") == 0) { 128 | keypad_set_type(KEYPAD_84); 129 | cur_cfg += strlen("84"); 130 | } else if(L_STRNCMP(cur_cfg, "old") == 0) { 131 | keypad_set_type(KEYPAD_OLD_NSPIRE); 132 | cur_cfg += strlen("old"); 133 | } else if(L_STRNCMP(cur_cfg, "default") == 0) { 134 | keypad_set_type(KEYPAD_NSPIRE); 135 | cur_cfg += strlen("default"); 136 | } 137 | } 138 | while(*cur_cfg != '\n' && *cur_cfg != '\0') cur_cfg++; 139 | cur_cfg++; 140 | } 141 | free(cfg); 142 | } else { 143 | puts("Couldn't read config file; using default settings"); 144 | } 145 | 146 | int l = strlen(argv[1]); 147 | char *extn = argv[1] + l - 4 - 4; 148 | char *load_file = argv[1];//[256]; 149 | 150 | uint8_t sfnl = strlen(load_file);//fgetc(savefile); 151 | char *romfn = malloc(sfnl+1); 152 | memcpy(romfn, load_file, sfnl+1); 153 | memcpy(romfn + sfnl - 8, "8rom", 4); 154 | 155 | FILE *l_romfile; 156 | if(!(l_romfile = fopen(romfn, "rb"))){ 157 | show_msgbox("Error", "Could not open rom"); 158 | return 1; 159 | } 160 | fseek(l_romfile, 0, SEEK_END); 161 | unsigned romsize = ftell(l_romfile); 162 | fclose(l_romfile); 163 | 164 | unsigned j; 165 | for(j = 0; j < N_CALC_TYPES; j++) { 166 | if (calc_types[j].flash_size == romsize) { 167 | g_calc = calc_types[j]; 168 | break; 169 | } 170 | } 171 | 172 | printf("begin\n"); 173 | mmu_init(); 174 | printf("mmu_init done\n"); 175 | #ifndef NO_LCD 176 | if (g_calc.cselcd) { 177 | cselcd_init(); 178 | } else { 179 | m_lcd_init(); 180 | } 181 | #endif 182 | cpu_init(); 183 | 184 | io_init(); 185 | printf("lcd, cpu, io done\n"); 186 | 187 | /*if(strncmp(extn, "8lnk", 4) == 0) { 188 | FILE *lnkfile; 189 | if(!(lnkfile = fopen(argv[1], "rb"))){ 190 | show_msgbox("Error", "Could not open link"); 191 | return 1; 192 | } 193 | int n = fread(load_file, 1, 255, lnkfile); 194 | load_file[n] = 0; 195 | extn = load_file + n - 4 - 4; 196 | } else {*/ 197 | //size_t l2 = strlen(argv[1]); 198 | //if(l2 > 255) l2 = 255; 199 | //memcpy(load_file, argv[1], l2); 200 | /* load_file[l2] = 0; 201 | extn = load_file + l2 - 4 - 4; 202 | 203 | FILE *newlnk = fopen(); 204 | }*/ 205 | 206 | if(strncmp(extn, "8sav", 4) == 0){ 207 | savestate_load(load_file, romfn); 208 | }else{ 209 | FILE *romfile; 210 | if(!(romfile = fopen(load_file, "rb"))){ 211 | show_msgbox("Error", "Could not open rom"); 212 | return 1; 213 | } 214 | //printf("%d\n", romsize); 215 | //flash = calloc(0x20000, 1); 216 | printf("flash=%p\n", flash); 217 | fread(flash, sizeof(char), romsize, romfile); 218 | fclose(romfile); 219 | clear_cache(); 220 | } 221 | 222 | speedcontrol_init(); 223 | interrupt_init(); 224 | //memset(REAL_SCREEN_BASE_ADDRESS, 2, 100); 225 | int cycles_to_run = timer_after(0); 226 | int i = 0; 227 | 228 | timer_set_enabled(1); 229 | timer_freq_set(3); 230 | // uint32_t *mem32 = (uint32_t *)0xe0000000; 231 | // printf("%08x %08x %08x\n", mem32[0], mem32[1], mem32[2]); 232 | // asm volatile("b .\n\t"); 233 | while(1){ 234 | speedcontrol_before(); 235 | //printf("%d\n", cycles_to_run); 236 | int cycles_left = /*(ZCpu.Z80IF & Z80_HALT) && (ZCpu.Z80_IRQ == 0) ? 0 : */DrZ80Run(&ZCpu, cycles_to_run); 237 | int cycles_elapsed = cycles_to_run == cycles_left ? 10000 : cycles_to_run - cycles_left; 238 | /*if(isKeyPressed(KEY_NSPIRE_CAT)) { 239 | char *pc = (char *)ZCpu.Z80PC; 240 | int pcb = ZCpu.Z80PC - ZCpu.Z80PC_BASE; 241 | printf("%d %d %04x %02x%02x%02x%02x\n", i++, cycles_elapsed, pcb, pc[0], pc[1], pc[2], pc[3]);//, ZCpu.Z80BC); 242 | printf("a %02x f %02x bc %04x de %04x hl %04x\n", ZCpu.Z80A >> 24, ZCpu.Z80F >> 24, ZCpu.Z80BC >> 16, ZCpu.Z80DE >> 16, ZCpu.Z80HL >> 16); 243 | printf("sp %04x ix %04x iy %04x\n", ZCpu.Z80SP - ZCpu.Z80SP_BASE, ZCpu.Z80IX >> 16, ZCpu.Z80IY >> 16); 244 | } 245 | 246 | port_debug = isKeyPressed(KEY_NSPIRE_P);*/ 247 | //if(aaa) { 248 | // puts("aaa"); 249 | // aaa = 0; 250 | //} 251 | cycles_to_run = timer_after(cycles_elapsed); 252 | if(isKeyPressed(KEY_NSPIRE_ESC)) break; 253 | speedcontrol_after(cycles_elapsed); 254 | } 255 | interrupt_end(); 256 | 257 | savestate_save(romfn); 258 | free(romfn); 259 | #ifndef NO_LCD 260 | if (g_calc.cselcd) { 261 | cselcd_end(); 262 | } else { 263 | lcd_end(); 264 | } 265 | #endif 266 | speedcontrol_end(); 267 | mmu_end(); 268 | #ifdef USE_NAVNETIO 269 | navnet_io_end(g_stream); 270 | #endif 271 | 272 | return 0; 273 | } 274 | 275 | void cpu_trace() { 276 | uint8_t *pc = (uint8_t *)ZCpu.Z80PC; 277 | printf("XX XX %04x %02x%02x%02x%02x\n", (uintptr_t)(pc - ZCpu.Z80PC_BASE), pc[0], pc[1], pc[2], pc[3]);//, ZCpu.Z80BC); 278 | printf("a %02x f %02x bc %04x de %04x hl %04x\n", ZCpu.Z80A >> 24, ZCpu.Z80F >> 24, ZCpu.Z80BC >> 16, ZCpu.Z80DE >> 16, ZCpu.Z80HL >> 16); 279 | printf("sp %04x ix %04x iy %04x\n", ZCpu.Z80SP - ZCpu.Z80SP_BASE, ZCpu.Z80IX >> 16, ZCpu.Z80IY >> 16); 280 | } 281 | 282 | void cpu_init(){ 283 | memset(&ZCpu, 0, sizeof(ZCpu)); 284 | ZCpu.z80_rebasePC= cpu_rebasePC; 285 | ZCpu.z80_rebaseSP= cpu_rebaseSP; 286 | ZCpu.z80_read8 = cpu_read8; 287 | ZCpu.z80_read16 = cpu_read16; 288 | ZCpu.z80_write8 = cpu_write8; 289 | ZCpu.z80_write16 = cpu_write16; 290 | ZCpu.z80_in =cpu_in; 291 | ZCpu.z80_out =cpu_out; 292 | ZCpu.z80_irq_callback = cpu_irq_callback; 293 | ZCpu.z80_trace = cpu_trace; 294 | ZCpu.Z80PC = 0xe0000000;//cpu_rebasePC(0); 295 | ZCpu.Z80PC_BASE = 0xe0000000;//cpu_rebasePC(0); 296 | ZCpu.Z80SP = 0xe000ffff;//cpu_rebaseSP(0xffff); 297 | ZCpu.Z80SP_BASE = 0xe0000000;//cpu_rebaseSP(0); 298 | } 299 | 300 | void cpu_irq_callback(){ 301 | //printf("irq\n"); 302 | int_callback(); 303 | } 304 | 305 | /*void pdb(unsigned int pc){ 306 | printf("pc(a) %02x v %04x\n", pc, cpu_read16(pc)); 307 | }*/ 308 | 309 | void * null_rebasePC(uint16_t x) { 310 | return Z80_MEM_BASE + (x & 0xffff); 311 | } 312 | 313 | void * cpu_rebasePC(uint16_t x){ 314 | #ifdef DRZ80MEM_DEBUG 315 | if(x & ~0xffff) 316 | printf("Invalid rebasePC: %08x\n", x); 317 | #endif 318 | //if(x == 0) printf("reset\n"); 319 | //printf("rebasePC 0x%04x\n", x); 320 | //ZCpu.Z80PC_BASE = (unsigned int)flash; 321 | //if(mmap_check_endboot(x)) ZCpu.z80_rebasePC = NULL; 322 | x &= 0xffff; 323 | if(mmap_check_endboot(x)) ZCpu.z80_rebasePC = null_rebasePC; 324 | //ZCpu.Z80PC_BASE = (unsigned int)mmap_base_addr(x); 325 | //if(ZCpu.Z80PC_BASE + (x & 0x3FFF) != flash + x) printf("pc %08x %p\n", ZCpu.Z80PC_BASE + (x & 0x3FFF), flash + x); 326 | //printf("pc %p %08x\n", mmap_bank_for_addr(x) + (x & 0x3FFF), ZCpu.Z80PC_BASE + x); 327 | //return ZCpu.Z80PC_BASE + x; 328 | return Z80_MEM_BASE + x; 329 | } 330 | 331 | void * cpu_rebaseSP(uint16_t x){ 332 | #ifdef DRZ80MEM_DEBUG 333 | if(x & ~0xffff) 334 | printf("Invalid rebaseSP: %08x\n", x); 335 | #endif 336 | //printf("rebaseSP 0x%lx\n", x); 337 | //ZCpu.Z80SP_BASE = (unsigned int)flash; 338 | //ZCpu.Z80SP_BASE = (unsigned int)mmap_base_addr(x); 339 | //if(ZCpu.Z80SP_BASE + (x & 0x3FFF) != flash + x) printf("sp %08x %p\n", ZCpu.Z80SP_BASE + (x & 0x3FFF), flash + x); 340 | //return ZCpu.Z80SP_BASE + x; 341 | return Z80_MEM_BASE + (x & 0xffff);//=(x & 0x3FFF); 342 | } 343 | 344 | unsigned short cpu_read16(uint16_t idx){ 345 | //asm(" b ."); 346 | //uint8_t *p = flash+idx; 347 | //if(mmap_z80_to_arm(idx) != flash+idx) printf("read16 0x%x\n", idx); 348 | uint8_t *p = Z80_MEM_BASE + (idx & 0xffff); 349 | #ifdef DRZ80MEM_DEBUG 350 | if(idx & ~0xffff) 351 | printf("Invalid read16: %p %04x\n", p, idx); 352 | #endif 353 | uint16_t val = p[0] | p[1] << 8; 354 | #ifdef MEM16_DEBUG 355 | printf("Read %04x at %08x\n", val, p); 356 | #endif 357 | /*if(idx < 0x4000) { 358 | uint8_t *p2; 359 | for(p2 = p - 8; p2 < p + 8; p2++) { 360 | printf("%02x ", *p2); 361 | } 362 | printf("\n"); 363 | printf("read16 %p 0x%04x -> %02x %02x = 0x%04x\n", p, idx, p[1], p[0], val); 364 | asm volatile("b .\n\t"); 365 | } 366 | val = p[0] | p[1] << 8; 367 | printf("read16 2.0 %p 0x%04x -> %02x %02x = 0x%04x\n", p, idx, p[1], p[0], val);*/ 368 | return val; 369 | } 370 | unsigned char cpu_read8(uint16_t idx){ 371 | //return flash[idx]; 372 | //if(mmap_z80_to_arm(idx) != flash+idx) printf("read8 0x%x\n", idx); 373 | uint8_t *p = Z80_MEM_BASE + idx;//(idx & 0xffff); 374 | #ifdef DRZ80MEM_DEBUG 375 | if(idx & ~0xffff) 376 | printf("Invalid read8: %p %04x\n", p, idx); 377 | #endif 378 | uint8_t val = *p; 379 | //if(idx < 0x4000) printf("read8 0x%04x -> %02x\n", idx, val); 380 | return val; 381 | } 382 | 383 | void cpu_write16(unsigned short val, uint16_t idx){ 384 | uint8_t *p = Z80_MEM_BASE + (idx & 0xffff); 385 | #ifdef MEM16_DEBUG 386 | printf("Wrt %04x at %08x\n", val, p); 387 | #endif 388 | //if(!((p >= flash && p < flash + FLASH_SIZE) || (p >= ram && p < ram + RAM_SIZE))) 389 | #ifdef DRZ80MEM_DEBUG 390 | if(idx & ~0xffff) { 391 | printf("Invalid write16: %p %04x\n", p, idx); 392 | //cpu_trace(); 393 | //asm("bkpt\n\t"); 394 | } 395 | #endif 396 | //if(idx < 0x4000) printf("write16 %p 0x%04x 0x%04x\n", p, idx, val); 397 | //uint8_t *p = flash + idx; 398 | p[0] = val & 0xff; 399 | p[1] = val >> 8; 400 | } 401 | 402 | void cpu_write8(unsigned char val, uint16_t idx){ 403 | uint8_t *p = Z80_MEM_BASE + (idx & 0xffff); 404 | //if(!((p >= flash && p < flash + FLASH_SIZE) || (p >= ram && p < ram + RAM_SIZE))) 405 | #ifdef DRZ80MEM_DEBUG 406 | if(idx & ~0xffff) 407 | printf("Invalid write8: %p %04x\n", p, idx); 408 | #endif 409 | //if(idx < 0x4000) printf("write8 0x%04x 0x%02x\n", idx, val); 410 | *p = val; 411 | //flash[idx] = val; 412 | } 413 | /*unsigned char cpu_in(unsigned short port){ 414 | port &= 0xff; 415 | uint8_t x = cpu_in_(port); 416 | //if(port == 1) printf("in %x %x\n", port, x); 417 | return x; 418 | }*/ 419 | unsigned char cpu_in(unsigned short pn_){ 420 | uint8_t pn = (uint8_t)pn_; 421 | struct z80port *p = &ports[pn]; 422 | uint8_t v = port_get(pn, p); 423 | if(port_debug) printf("Read %02x from port %02x (%s)\n", v, p->number, p->name); 424 | return v; 425 | } 426 | 427 | void cpu_out(unsigned short pn_, unsigned char val){ 428 | uint8_t pn = (uint8_t)pn_; 429 | struct z80port *p = &ports[pn]; 430 | //register uint8_t *temp asm("r0"); 431 | //asm(" mov r0, r6"); 432 | //uint16_t zpc = temp - ZCpu.Z80PC_BASE; 433 | if(port_debug) printf("Writing %02x to port %02x (%s)\n", val, p->number, p->name); 434 | port_set(pn, p, val); 435 | //temp = cpu_rebasePC(zpc); 436 | //asm(" mov r6, r0"); // do not try this at home 437 | } 438 | 439 | uint8_t port_get(uint8_t pn, struct z80port *p){ 440 | if(p->in.n) return p->in.n(pn); 441 | //if(p->n_in) return p->n_in(p->number); 442 | if(p->ptr_val) return *(p->ptr_val); 443 | if(p->mirror) return port_get(pn, p->mirror); 444 | return p->const_val; 445 | } 446 | 447 | void port_set(uint8_t pn, struct z80port *p, uint8_t val){ 448 | if(p->out.n) p->out.n(val, pn); 449 | //else if(p->n_out) p->n_out(p->number, val); 450 | else if(p->ptr_val) *(p->ptr_val) = val; 451 | else if(p->mirror) port_set(pn, p->mirror, val); 452 | } 453 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | #include "drz80.h" 2 | 3 | extern struct DrZ80 ZCpu; 4 | void * cpu_rebasePC(uint16_t x); 5 | -------------------------------------------------------------------------------- /src/mmu_mmap.c: -------------------------------------------------------------------------------- 1 | #include "mmu_mmap.h" 2 | 3 | #include 4 | #include 5 | #include "util.h" 6 | #include 7 | #include "c_syscall.h" 8 | #include "aligned_alloc.h" 9 | #include "lcd.h" 10 | 11 | #define RAM_SIZE 0x20000 12 | #define PAGE_SIZE 0x4000 13 | #define FLASH_PAGES (FLASH_SIZE / PAGE_SIZE) 14 | 15 | static void *get_mmu_addr() { 16 | void *v; 17 | asm volatile( 18 | "mrc p15, 0, %0, c2, c0, 0\n\t" 19 | : "=r"(v)); 20 | return v; 21 | } 22 | 23 | static void set_mmu_addr(void *a) { 24 | asm volatile( 25 | "mcr p15, 0, %0, c2, c0, 0\n\t" 26 | :: "r"(a)); 27 | } 28 | 29 | static void invalidate_tlb_all() { 30 | asm volatile( 31 | " mcr p15, 0, %0, c8, c6, 0\n" ::"r"(0) 32 | ); 33 | } 34 | 35 | static void clean_dcache_all() { 36 | asm volatile( 37 | "1: mrc p15, 0, r15, c7, c10, 3\n" //test and clean 38 | " bne 1b\n" 39 | ::: "cc"); // modifies condition codes 40 | } 41 | 42 | static void clean_inval_dcache_all() { 43 | asm volatile( 44 | "1: mrc p15, 0, r15, c7, c14, 3\n" //test and clean 45 | " bne 1b\n" 46 | ::: "cc"); // modifies condition codes 47 | 48 | } 49 | 50 | static void clean_inval_dcache(void *a) { 51 | asm volatile( 52 | " mcr p15, 0, %0, c7, c14, 1\n" 53 | ::"r"(a)); 54 | } 55 | 56 | static uint32_t get_cache_type() { 57 | uint32_t v; 58 | asm volatile( 59 | " mrc p15,0,%0,c0,c0,1\n" 60 | :"=r"(v)); 61 | return v; 62 | } 63 | 64 | 65 | static void invalidate_tlb(void *a) { 66 | asm volatile( 67 | " mcr p15, 0, %0, c8, c6, 1\n" 68 | :: "r"(a)); 69 | } 70 | 71 | 72 | static uint32_t get_cr1() { 73 | uint32_t v; 74 | asm volatile( 75 | "mrc p15, 0, %0, c1, c0, 0\n\t" 76 | : "=r"(v)); 77 | return v; 78 | } 79 | 80 | static void set_cr1(uint32_t v) { 81 | asm volatile( 82 | "mcr p15, 0, %0, c1, c0, 0\n\t" 83 | ::"r"(v)); 84 | } 85 | 86 | static uint32_t get_cr3() { 87 | uint32_t v; 88 | asm volatile( 89 | "mrc p15, 0, %0, c3, c0, 0\n\t" 90 | : "=r"(v)); 91 | return v; 92 | } 93 | 94 | static void set_cr3(uint32_t v) { 95 | asm volatile( 96 | "mcr p15, 0, %0, c3, c0, 0\n\t" 97 | ::"r"(v)); 98 | } 99 | 100 | #include "_syscalls.h" 101 | 102 | uint8_t *mem_base; 103 | uint32_t *section_base; 104 | uint32_t *section_base_l; 105 | 106 | uint32_t *m_section_base = (uint32_t *)0xe0040400; 107 | 108 | aligned_ptr mem_base_al; 109 | aligned_ptr section_base_al; 110 | aligned_ptr section_base_l_al; 111 | 112 | int n_sections; 113 | uint32_t *mmu_base; 114 | unsigned normal = 0; 115 | static unsigned mmu_mode = 0; 116 | unsigned testing = 0; 117 | unsigned uses_hi_ram = 0; 118 | 119 | /*int main(void) { 120 | mmu_init(); 121 | mmu_end(); 122 | }*/ 123 | 124 | static void *RAM_PAGE(unsigned x) { 125 | void *b = mem_base + FLASH_SIZE + (0x4000 * x); 126 | #ifdef MMU_DEBUG 127 | if((uintptr_t)b - (uintptr_t)mem_base >= FLASH_SIZE + RAM_SIZE) printf("illegal start of ram page %02x %p - b=%p!\n", x, b, mem_base); 128 | if((uintptr_t)b - (uintptr_t)mem_base + 0x4000 > FLASH_SIZE + RAM_SIZE) printf("illegal end of ram page %02x %p - b=%p!\n", x, b, mem_base); 129 | #endif 130 | return b; 131 | } 132 | static void *ROM_PAGE(unsigned x) { 133 | void *b = mem_base + (0x4000 * x); 134 | #ifdef MMU_DEBUG 135 | if((uintptr_t)b - (uintptr_t)mem_base >= FLASH_SIZE + RAM_SIZE) printf("illegal start of rom page %02x %p - b=%p!\n", x, b, mem_base); 136 | if((uintptr_t)b - (uintptr_t)mem_base + 0x4000 > FLASH_SIZE + RAM_SIZE) printf("illegal end of rom page %02x %p - b=%p!\n", x, b, mem_base); 137 | #endif 138 | return b; 139 | } 140 | //#define RAM_PAGE(x) (mem_base + FLASH_SIZE + (0x4000 * (x))) 141 | //#define ROM_PAGE(x) (mem_base + (0x4000 * (x))) 142 | 143 | static void update67(); 144 | 145 | static void map_in(int idx, void *base, bool ro) { 146 | //puts("map_in a"); 147 | int i; 148 | uintptr_t b2 = (uintptr_t)base & ~0xfff; 149 | uint32_t* sb = m_section_base + idx * 4; 150 | //uint32_t* sbl = m_section_base_l + 0xf0 + idx * 4; 151 | if((sb[0] & ~0xfff) == b2) { 152 | //puts("map_in b"); 153 | return; 154 | } 155 | //printf("mapping %04x -> %02x\n", idx * 0x4000, ((uint8_t *)base - mem_base) / 0x4000); 156 | #ifdef MMU_DEBUG 157 | if(!testing) printf("mapping %p -> %p = %p (%p, %02x)\n", Z80_MEM_BASE + (idx * 0x4000), base, b2, (uint8_t *)base - mem_base, ((uint8_t *)base - mem_base) / 0x4000); 158 | #endif 159 | //if(b2 - (uintptr_t)mem_base > FLASH_SIZE + RAM_SIZE) printf("illegal start of page %04x %p - b=%p!\n", idx * 0x4000, base, mem_base); 160 | //if(b2 - (uintptr_t)mem_base + 0x4000 > FLASH_SIZE + RAM_SIZE) printf("illegal end of page %04x %p - b=%p!\n", idx * 0x4000, base, mem_base); 161 | uint32_t *mb = (uint32_t *)(Z80_MEM_BASE + idx * 0x4000); 162 | 163 | // flush cached entries from old mapping to RAM 164 | #ifndef EMU_BUILD 165 | int j; 166 | for(j = 0; j < 0x4000; j += 8) { 167 | clean_inval_dcache(mb + j); 168 | } 169 | #else 170 | clean_inval_dcache_all(); 171 | #endif 172 | 173 | for(i = 0; i < 4; i++) { 174 | uint32_t v = (b2 + 0x1000 * i) | 0b1110 | (ro ? 0 : 0xff0); 175 | sb[i-16] = sb[i] = sb[i+16] = v; 176 | } 177 | // translation table is write-through, so cache clear isn't necessary 178 | //clean_inval_dcache_all(); 179 | 180 | // clear TLB for newly-mapped page 181 | for(i = 0; i < 16; i++) { 182 | invalidate_tlb(mb + i * 0x100); 183 | } 184 | } 185 | 186 | void map_framebuffer(void *buf) { 187 | int i, j; 188 | uintptr_t bb = (uintptr_t)buf; 189 | for(i = 0, j=0; i < FB_SIZE; i += 0x1000, j++) { 190 | m_section_base[0x50+j] = (bb + i) | 0b1010 | 0xff0; 191 | } 192 | for(i = 0; i < FB_SIZE; i += 0x400) { 193 | invalidate_tlb((uint8_t *)0xe0050000 + i); 194 | } 195 | } 196 | 197 | struct bank { 198 | uint8_t low; 199 | uint8_t hi; 200 | }; 201 | 202 | 203 | static unsigned off_for_bank(struct bank b) { 204 | return b.low & 0x80 ? (unsigned)b.low - 0x80 + FLASH_PAGES : (unsigned)b.low | ((unsigned)b.hi & EF_MASK) << 7; 205 | } 206 | 207 | static void map_page(int idx, unsigned page) { 208 | //print("map_page idx %d page %d\n", idx, page); 209 | if(page > FLASH_PAGES + 3) uses_hi_ram = 1; 210 | map_in(idx, ROM_PAGE(page), page < FLASH_PAGES); 211 | } 212 | 213 | static void map_page_st(int idx, struct bank page) { 214 | map_page(idx, off_for_bank(page)); 215 | } 216 | 217 | unsigned mmap_check_endboot(uint16_t pc){ 218 | //printf("j %04x\n", pc); 219 | if(normal) return 1; 220 | if(pc >= 0x4000 && pc < (mmu_mode ? 0xC000 : 0x8000)){ 221 | printf("end boot\n"); 222 | normal = 1; 223 | map_in(0, ROM_PAGE(0), 1); 224 | } 225 | return normal; 226 | } 227 | 228 | uint8_t *flash; 229 | uint8_t *ram; 230 | 231 | void mmap_set_mode(uint8_t mode){ 232 | #ifdef MMU_DEBUG 233 | printf("mmu mode -> %d\n", mode); 234 | #endif 235 | mmu_mode = mode; 236 | update67(); 237 | } 238 | static int bfp(int p){ 239 | switch(p){ 240 | case 5: return 2; 241 | case 6: return 0; 242 | case 7: return 1; 243 | } 244 | return 0; 245 | } 246 | 247 | struct bank banks[3] = {0}; 248 | 249 | 250 | uint8_t mmap_in(uint8_t port){ 251 | //printf("%d -> %02x\n", port, banks[bfp(port)]); 252 | if(port == 5) return banks[2].low & ~0x80; 253 | return banks[bfp(port)].low; 254 | } 255 | 256 | #ifdef MMU_DEBUG 257 | void empirical_map_test(uint16_t *a, uint16_t b) { 258 | int i; 259 | for(i = 0; i < 0x2000; i++) { 260 | uint16_t r = rand(); 261 | a[i] = r;//(uint16_t)(r >> 8) | (uint16_t)(r << 8); 262 | uint16_t bb = cpu_read16(b + i * 2); 263 | if(bb != r) { 264 | printf("not consistent - %p = %04x, 0x%04x = %04x\n", a + i, r, b + i * 2, bb); 265 | //sleep(50); 266 | } 267 | } 268 | } 269 | 270 | void mmu_test() { 271 | testing = 1; 272 | printf("mmu test\n"); 273 | mmap_set_mode(0); 274 | int i; 275 | for(i = 0; i < 0x08; i++) { 276 | mmu_port5_out(i); 277 | empirical_map_test(RAM_PAGE(i), 0xc000); 278 | } 279 | for(i = 0; i < 0x80; i++) { 280 | mmu_port67_out(i, 6); 281 | empirical_map_test(ROM_PAGE(i), 0x4000); 282 | } 283 | for(i = 0; i < 0x80; i++) { 284 | mmu_port67_out(i, 7); 285 | empirical_map_test(ROM_PAGE(i), 0x8000); 286 | } 287 | printf("end mmu test\n"); 288 | testing = 0; 289 | } 290 | #endif 291 | 292 | #define STR(x) #x 293 | #define SF(x) STR(x) 294 | 295 | void __attribute__((interrupt("ABORT"), naked)) abort_handler(){ 296 | asm volatile( 297 | "push {r0, r1, r2}\n" // r2 is placeholder 298 | " mrc p15, 0, r0, c6, c0, 0\n" 299 | " subs r0, #" SF(I_Z80_MEM_BASE) "\n" 300 | " rsbges r0, r0, #0x10000\n" 301 | " popge {r0, r1, r2}\n" 302 | " subges pc, lr, #4\n" 303 | " ldr r0, o_dah\n" 304 | " str r0, [sp, #8]\n" 305 | " pop {r0, r1, pc}\n" 306 | "o_dah: .word 0\n" 307 | ); 308 | } 309 | 310 | extern void (*o_dah)(void); 311 | 312 | //typedef volatile void * vvptr; 313 | 314 | void mprotect_init() { 315 | volatile void **ivt = (volatile void **)0x20; 316 | o_dah = ivt[4]; 317 | //printf("o_dah = %08x\n", o_dah); 318 | ivt[4] = abort_handler; 319 | } 320 | 321 | void mprotect_end() { 322 | volatile void **ivt = (volatile void **)0x20; 323 | ivt[4] = o_dah; 324 | } 325 | 326 | void mmu_init() { 327 | mprotect_init(); 328 | mmu_base = get_mmu_addr(); 329 | printf("mmu_base %p\n", mmu_base); 330 | mem_base_al = x_aligned_alloc(0x1000, RAM_SIZE + FLASH_SIZE); 331 | mem_base = mem_base_al.ptr; 332 | int t2_size = 0x100; 333 | section_base_al = x_aligned_alloc(0x1000, 2 * 4 * t2_size); 334 | //section_base_l_al = x_aligned_alloc(0x400, 4 * t2_size); 335 | 336 | section_base_l = section_base_al.ptr; 337 | section_base = section_base_l + t2_size;//section_base_l_al.ptr; 338 | int i; 339 | for(i = 0; i < t2_size; i++) { 340 | section_base[i] = 0; 341 | } 342 | for(i = 0; i < t2_size; i++) { 343 | section_base_l[i] = 0; 344 | } 345 | printf("section_base=%p section_base_l=%p\n", section_base, section_base_l); 346 | section_base[0x40] = (uintptr_t)section_base | 0b111111111010; // write-through cache, full permissions 347 | //section_base[0xf1] = (uintptr_t)section_base_l | 0b111011; 348 | 349 | uint32_t aa = get_cr1(); 350 | printf("cr1=%08lx cr3=%08lx\n", aa, get_cr3()); 351 | set_cr1(aa | 1<<9); // enable ROM protection 352 | //printf("cr1 = %08x", get_cr1()); 353 | memset(mem_base, 0, RAM_SIZE + FLASH_SIZE); 354 | //invalidate_tlb_all(); 355 | 356 | /*mmu_port5_out(0); 357 | mmu_port67_out(0, 6); 358 | mmu_port67_out(0, 7);*/ 359 | 360 | // domain 1, Client mode 361 | set_cr3(get_cr3() | (1 << 2)); 362 | mmu_base[0xdff] = (uintptr_t)section_base_l | 0b000110001; 363 | mmu_base[0xe00] = (uintptr_t)section_base | 0b000110001; 364 | clean_inval_dcache_all(); 365 | invalidate_tlb_all(); 366 | //invalidate_tlb(0xe00f0000); 367 | //invalidate_tlb(0xe00f1000); 368 | 369 | //asm(" bkpt #1\n"); 370 | map_in(0, ROM_PAGE(BOOT_PAGE), 1); 371 | 372 | flash = mem_base; 373 | ram = mem_base + FLASH_SIZE; 374 | printf("flash = %p, ram = %p\n", flash, ram); 375 | #ifdef MMU_DEBUG 376 | //mmu_test(); 377 | #endif 378 | mmu_port5_out(0); 379 | mmu_port67_out(0, 6); 380 | mmu_port67_out(0, 7); 381 | //asm(" bkpt #0\n"); 382 | //*(uint32_t *)0xe0000000 = 0x12345678; 383 | //*(volatile uint32_t *)0xef000000 = 0xffffffff; 384 | } 385 | 386 | 387 | static void update67() { 388 | if(mmu_mode == 0) { 389 | map_page_st(1, banks[0]); 390 | map_page_st(2, banks[1]); 391 | map_page_st(3, banks[2]); 392 | } else { 393 | map_page(1, off_for_bank(banks[0]) & ~1); 394 | map_page(2, off_for_bank(banks[0]) | 1); 395 | map_page_st(3, banks[1]); 396 | } 397 | //clear_cache(); 398 | } 399 | 400 | static void mmu_port5_update() { 401 | if(mmu_mode == 0) { 402 | map_page_st(3, banks[2]); 403 | //clear_cache(); 404 | } 405 | } 406 | 407 | void mmu_port5_out(uint8_t val) { 408 | #ifdef MMU_DEBUG 409 | if(!testing) printf("wrote %02x to port 05\n", val); 410 | #endif 411 | banks[2].low = val | 0x80; 412 | mmu_port5_update(); 413 | } 414 | 415 | static void mmu_port67_update(uint8_t port) { 416 | if(mmu_mode == 0) { 417 | map_page_st(port, banks[port - 1]); 418 | } else if(port == 1) { 419 | map_page(1, off_for_bank(banks[0]) & ~1); 420 | map_page(2, off_for_bank(banks[0]) | 1); 421 | } else if(port == 2) { 422 | map_page_st(3, banks[1]); 423 | } 424 | } 425 | 426 | void mmu_port67_out(uint8_t val, uint8_t port) { 427 | #ifdef MMU_DEBUG 428 | if(!testing) printf("wrote %02x to port %02x\n", val, port); 429 | #endif 430 | banks[port - 6].low = val; 431 | mmu_port67_update(port - 5); 432 | //clear_cache(); 433 | } 434 | 435 | void mmu_portEF_out(uint8_t val, uint8_t port) { 436 | #ifdef MMU_DEBUG 437 | if(!testing) printf("wrote %02x to port %02x\n", val, port); 438 | #endif 439 | banks[port - 0xe].hi = val; 440 | mmu_port67_update(port - 0xd); 441 | } 442 | 443 | uint8_t mmu_portEF_in(uint8_t port) { 444 | return banks[port - 0xe].hi; 445 | } 446 | 447 | void mmu_end() { 448 | //int i; 449 | clean_inval_dcache_all(); 450 | mmu_base[0xdff] = 0; 451 | mmu_base[0xe00] = 0; 452 | //clear_cache(); 453 | set_cr3(get_cr3() & ~(1 << 2)); 454 | set_cr1(get_cr1() & ~(1<<9)); // disable ROM protection 455 | mprotect_end(); 456 | x_aligned_free(section_base_al); 457 | x_aligned_free(mem_base_al); 458 | } 459 | 460 | void mmap_save(FILE *f) { 461 | fputc(mmu_mode, f); 462 | FWRITE_VALUE(banks, f); 463 | fputc(normal, f); 464 | } 465 | 466 | void mmap_restore(FILE *f) { 467 | mmu_mode = fgetc(f); 468 | FREAD_VALUE(&banks, f); 469 | mmu_port5_update(); 470 | mmu_port67_update(1); 471 | mmu_port67_update(2); 472 | normal = fgetc(f); 473 | if(normal) map_in(0, ROM_PAGE(0), 1); 474 | } 475 | -------------------------------------------------------------------------------- /src/mmu_mmap.h: -------------------------------------------------------------------------------- 1 | #ifndef MMU_MMAP_H 2 | #define MMU_MMAP_H 3 | #include 4 | #include 5 | 6 | #include "calctype.h" 7 | 8 | void mmu_port67_out(uint8_t val, uint8_t port); 9 | void mmu_port5_out(uint8_t val); 10 | uint8_t mmap_in(uint8_t port); 11 | 12 | void mmu_portEF_out(uint8_t val, uint8_t port); 13 | uint8_t mmu_portEF_in(uint8_t port); 14 | 15 | void map_framebuffer(void *buf); 16 | 17 | unsigned mmap_check_endboot(uint16_t pc); 18 | void mmap_set_mode(uint8_t mode); 19 | 20 | void mmu_init(); 21 | void mmu_end(); 22 | 23 | void mmap_save(FILE *f); 24 | void mmap_restore(FILE *f); 25 | 26 | extern uint8_t *flash; 27 | extern uint8_t *ram; 28 | extern unsigned uses_hi_ram; 29 | 30 | #define I_Z80_MEM_BASE 0xe0000000 31 | #define Z80_MEM_BASE ((uint8_t *)I_Z80_MEM_BASE) 32 | 33 | #endif -------------------------------------------------------------------------------- /src/navnet-defs.h: -------------------------------------------------------------------------------- 1 | #ifndef NAVNET_DEFS_H 2 | #define NAVNET_DEFS_H 3 | 4 | #define TI_NN_SUCCESS 1 5 | #define TI_NN_ENUM_DONE 2 6 | #define TI_NN_NOT_SUPPORTED 6 7 | #define TI_NN_ERR_STORAGE_FULL -1 8 | #define TI_NN_ERR_UNKNOWN -2 9 | #define TI_NN_ERR_VERSION -3 10 | #define TI_NN_ERR_NOT_SUBSCRIBED -4 11 | #define TI_NN_ERR_INVALID_SESSION -5 12 | #define TI_NN_ERR_DATA_CORRUPTED -208 13 | #define TI_NN_ERR_OUT_MEMORY -256 14 | #define TI_NN_ERR_INVALID_CONNECTION -257 15 | #define TI_NN_ERR_INCOMPLETE_TRANSACTION -258 16 | #define TI_NN_ERR_NODE_UNRESPONSIVE -259 17 | #define TI_NN_ERR_DATA_SIZE_EXCEEDED -261 18 | #define TI_NN_ERR_NOT_SUPPORTED -262 19 | #define TI_NN_ERR_INVALID_OPERATION -263 20 | #define TI_NN_ERR_FILE_NOT_FOUND -264 21 | #define TI_NN_ERR_ILLEGAL_ARGUMENT -265 22 | #define TI_NN_ERR_OPERATION_CANCELLED -266 23 | #define TI_NN_ERR_INVALID_STATE -267 24 | #define TI_NN_ERR_INVALID_NODE_HANDLE -268 25 | #define TI_NN_ERR_BUSY -269 26 | #define TI_NN_ERR_INVALID_FILE -270 27 | #define TI_NN_ERR_BATTERY -271 28 | #define TI_NN_ERR_LOGIN -272 29 | #define TI_NN_ERR_PROTOCOL -273 30 | #define TI_NN_ERR_ENUM_DONE -274 31 | #define TI_NN_ERR_DEST_FILE_NOT_FOUND -275 32 | #define TI_NN_ERR_DEST_INVALID_FILE -276 33 | #define TI_NN_ERR_FILE_NOT_ACCESSIBLE -277 34 | #define TI_NN_ERR_DEST_FILE_NOT_ACCESSIBLE -278 35 | #define TI_NN_ERR_PATH_EXISTS -279 36 | #define TI_NN_ERR_DIR_NOT_EMPTY -280 37 | #define TI_NN_INVALID_PORT -281 38 | #define TI_NN_ERR_PATH_NAME_TOO_LONG -282 39 | #define TI_NN_ERR_FOLDER_DEPTH -283 40 | #define TI_NN_ERR_FILE_TYPE -284 41 | #define TI_NN_ERR_ILLEGAL_CHAR_IN_NAME -285 42 | #define TI_NN_ERR_MULTIPLE_CALL -287 43 | #define TI_NN_ERR_MULTIPLE_CALL_DIFFERENT_PROCESS -288 44 | #define TI_NN_ERR_MHH_DEVICE_ERROR -289 45 | #define TI_NN_ERR_MHH_NETWORK_ERROR -290 46 | #define TI_NN_ERR_MHH_NOT_SUPPORTED_ERROR -291 47 | 48 | #endif -------------------------------------------------------------------------------- /src/navnet-io.c: -------------------------------------------------------------------------------- 1 | #include "navnet-io.h" 2 | 3 | #include 4 | #include 5 | #include "navnet-defs.h" 6 | 7 | #define VIC_BASE 0xDC000000 8 | #define _REG(base, x) *((volatile uint32_t *)(base + x)) 9 | #define VIC_REG(x) _REG(VIC_BASE, x) 10 | 11 | void **isr_addr = (void **)0x38; 12 | void *real_isr; 13 | uint32_t os_ints_enabled; 14 | 15 | void navnet_io_early() { 16 | os_ints_enabled = VIC_REG(0x10); 17 | real_isr = *isr_addr; 18 | } 19 | 20 | nn_stream navnet_io_init() { 21 | nn_oh_t oh = TI_NN_CreateOperationHandle(); 22 | if(TI_NN_NodeEnumInit(oh) != TI_NN_SUCCESS) return NULL; 23 | //puts("a"); 24 | nn_nh_t nh; 25 | if(TI_NN_NodeEnumNext(oh, &nh) != TI_NN_ENUM_DONE) return NULL; 26 | //puts("b"); 27 | if(TI_NN_NodeEnumDone(oh) != TI_NN_SUCCESS) return NULL; 28 | //puts("c"); 29 | if(TI_NN_DestroyOperationHandle(oh) != TI_NN_SUCCESS) return NULL; 30 | //puts("d"); 31 | nn_ch_t ch; 32 | if(TI_NN_Connect(nh, 0x4444, &ch) != TI_NN_SUCCESS) return NULL; 33 | //puts("e"); 34 | return ch; 35 | } 36 | 37 | static void irq_enable(){ 38 | unsigned dummy; 39 | __asm__ volatile( 40 | " mrs r0, cpsr\n" 41 | " bic r0, r0, #0x80\n" 42 | " msr cpsr_c, r0\n" : "=r"(dummy) 43 | ); 44 | } 45 | 46 | static void irq_disable(){ 47 | unsigned dummy; 48 | __asm__ volatile( 49 | " mrs %0, cpsr\n" 50 | " orr %0, %0, #0x80\n" 51 | " msr cpsr_c, %0\n" : "=r"(dummy) 52 | ); 53 | } 54 | 55 | static unsigned irq_status() { 56 | unsigned v; 57 | __asm__ volatile( 58 | " mrs %0, cpsr\n" 59 | " and %0, %0, #0x80\n" : "=r"(v) 60 | ); 61 | return v; 62 | } 63 | 64 | void navnet_io_end(nn_stream st) { 65 | TI_NN_Disconnect(st); 66 | } 67 | 68 | #include "_syscalls.h" 69 | void navnet_io_send(nn_stream st, char *buf, size_t len) { 70 | //__real_puts("nn_send enter"); 71 | //putc('a', stdout); 72 | unsigned io = irq_status(); 73 | if(!io) irq_disable(); 74 | void *c_i = *isr_addr; 75 | uint32_t cie = VIC_REG(0x10); 76 | VIC_REG(0x14) = ~0; 77 | VIC_REG(0x10) = os_ints_enabled & 1<<8; 78 | *isr_addr = real_isr; 79 | 80 | TI_NN_Write(st, buf, len); 81 | 82 | *isr_addr = c_i; 83 | VIC_REG(0x14) = ~0; 84 | VIC_REG(0x10) = cie; 85 | if(!io) irq_enable(); 86 | //putc('b', stdout); 87 | //__real_puts("nn_send exit"); 88 | } 89 | 90 | size_t navnet_io_vprintf(nn_stream st, const char *format, va_list args) { 91 | char buf[256]; 92 | size_t b = vsnprintf(buf, 256, format, args); 93 | if(b > 256) b = 256; 94 | navnet_io_send(st, buf, b+1); 95 | return b; 96 | } 97 | 98 | size_t navnet_io_printf(nn_stream st, const char *format, ...) { 99 | va_list args; 100 | va_start(args, format); 101 | size_t sz = navnet_io_vprintf(st, format, args); 102 | va_end(args); 103 | return sz; 104 | } 105 | -------------------------------------------------------------------------------- /src/navnet-io.h: -------------------------------------------------------------------------------- 1 | #ifndef NAVNET_IO_H 2 | #define NAVNET_IO_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef nn_ch_t nn_stream; 9 | 10 | void navnet_io_early(); 11 | 12 | nn_stream navnet_io_init(); 13 | 14 | void navnet_io_end(nn_stream st); 15 | 16 | void navnet_io_send(nn_stream st, char *buf, size_t len); 17 | 18 | size_t navnet_io_vprintf(nn_stream st, const char *format, va_list args); 19 | 20 | size_t navnet_io_printf(nn_stream st, const char *format, ...); 21 | 22 | #endif -------------------------------------------------------------------------------- /src/rtc.c: -------------------------------------------------------------------------------- 1 | #include "os.h" 2 | #include "util.h" 3 | 4 | int32_t rtc_diff = 0; 5 | union rtc_out { 6 | uint32_t v; 7 | uint8_t a[4]; 8 | }; 9 | 10 | union rtc_out rtc_out_v; 11 | 12 | volatile uint32_t *nspire_rtc = (uint32_t *)0x90090000; 13 | 14 | void rtc_out(uint8_t val, uint8_t port){ 15 | rtc_out_v.a[port-0x41] = val; 16 | rtc_diff = rtc_out_v.v - *nspire_rtc; 17 | } 18 | uint8_t rtc_out_in(uint8_t port){ 19 | return rtc_out_v.a[port-0x41]; 20 | } 21 | 22 | uint8_t rtc_in(uint8_t port){ 23 | uint32_t nv = (*nspire_rtc) + rtc_diff; 24 | return (nv >> ((port - 0x45) * 8)) & 0xff; 25 | //return ((uint8_t *)&nv)[port-0x45]; 26 | } 27 | 28 | void rtc_save(FILE *f){ 29 | FWRITE_VALUE(rtc_diff, f); 30 | } 31 | 32 | void rtc_restore(FILE *f){ 33 | FREAD_VALUE(&rtc_diff, f); 34 | } -------------------------------------------------------------------------------- /src/rtc.h: -------------------------------------------------------------------------------- 1 | void rtc_out(uint8_t val, uint8_t port); 2 | uint8_t rtc_out_in(uint8_t port); 3 | uint8_t rtc_in(uint8_t port); 4 | 5 | void rtc_save(FILE *f); 6 | void rtc_restore(FILE *f); -------------------------------------------------------------------------------- /src/savestate.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include "lcd.h" 4 | #include "io.h" 5 | #include "keypad.h" 6 | #include "mmu_mmap.h" 7 | #include "rtc.h" 8 | #include "timer.h" 9 | #include "z_interrupt.h" 10 | #include "drz80.h" 11 | #include "main.h" 12 | #include 13 | 14 | #define N_PAGES (FLASH_SIZE / 0x4000) 15 | 16 | void savestate_save(char *romfn){ 17 | int rnl = strlen(romfn); 18 | char savefn[rnl + 1]; 19 | memcpy(savefn, romfn, rnl + 1); 20 | memcpy(savefn + rnl - 8, "8sav", 4); 21 | //printf("Saving to %s\n", savefn); 22 | FILE *savefile = fopen(savefn, "wb"); 23 | printf("PC=%08x, rel=%08x\n", ZCpu.Z80PC, ZCpu.Z80PC - ZCpu.Z80PC_BASE); 24 | if(uses_hi_ram) puts("Uses high ram"); 25 | ZCpu.Z80PC -= ZCpu.Z80PC_BASE; 26 | fwrite(&ZCpu, sizeof(struct DrZ80Regs), 1, savefile); 27 | ZCpu.Z80PC += ZCpu.Z80PC_BASE; 28 | //fseek(savefile, sizeof(struct DrZ80Regs), SEEK_CUR); 29 | uint32_t *page = malloc(0x4000); 30 | uint32_t *f32 = (uint32_t *)flash; 31 | uint8_t *dps = calloc(N_PAGES, sizeof(uint8_t)); 32 | uint8_t ndp = 0; 33 | FILE *romfile = fopen(romfn, "rb"); 34 | unsigned i; 35 | unsigned fi = 0; 36 | for(i = 0; i < N_PAGES; i++){ 37 | fread(page, 0x4000, 1, romfile); 38 | unsigned j; 39 | for(j = 0; j < 0x1000; j++){ 40 | if(f32[fi++] != page[j]){ 41 | dps[i] = 1; 42 | ndp++; 43 | break; 44 | } 45 | } 46 | } 47 | free(page); 48 | fclose(romfile); 49 | //fputc(strlen(romfn), savefile); 50 | //fwrite(romfn, strlen(romfn), 1, savefile); 51 | fputc(ndp, savefile); 52 | for(i = 0; i < N_PAGES; i++){ 53 | if(dps[i]){ 54 | fputc(i, savefile); 55 | fwrite(&flash[i * 0x4000], 0x4000, 1, savefile); 56 | } 57 | } 58 | free(dps); 59 | fwrite(ram, RAM_SIZE, 1, savefile); 60 | lcd_save(savefile); 61 | io_save(savefile); 62 | keypad_save(savefile); 63 | mmap_save(savefile); 64 | int_save(savefile); 65 | rtc_save(savefile); 66 | timer_save(savefile); 67 | 68 | fclose(savefile); 69 | } 70 | 71 | void savestate_load(char *savefn, char *romfn){ 72 | printf("Starting savestate load\n"); 73 | FILE *savefile = fopen(savefn, "rb"); 74 | 75 | /*fseek(savefile, 0, SEEK_END); 76 | int ss = ftell(savefile); 77 | fseek(savefile, 0, 0); 78 | int qq; 79 | for(qq = 0; qq < ss; qq++){ 80 | printf("%02x", fgetc(savefile)); 81 | } 82 | fseek(savefile, 0, 0);*/ 83 | 84 | fread(&ZCpu, sizeof(struct DrZ80Regs), 1, savefile); 85 | //fseek(savefile, sizeof(struct DrZ80Regs), SEEK_CUR); 86 | uint16_t zpc = ZCpu.Z80PC; 87 | 88 | printf("Loading rom from %s\n", romfn); 89 | 90 | FILE *romfile = fopen(romfn, "rb"); 91 | fseek(romfile, 0, SEEK_END); 92 | int romsize = ftell(romfile); 93 | fseek(romfile, 0, 0); 94 | fread(flash, romsize, 1, romfile); 95 | fclose(romfile); 96 | 97 | 98 | //printf("Loaded rom\n"); 99 | 100 | uint8_t n_dirty_pages = fgetc(savefile); 101 | int i; 102 | for(i = 0; i < n_dirty_pages; i++){ 103 | uint8_t dp_n = fgetc(savefile); 104 | //printf("Loading dirty page %02x", dp_n); 105 | fread(&flash[dp_n * 0x4000], 0x4000, 1, savefile); 106 | } 107 | 108 | //printf("Loaded dirty pages\n"); 109 | fread(ram, RAM_SIZE, 1, savefile); 110 | //fseek(savefile, RAM_SIZE, SEEK_CUR); 111 | 112 | //printf("Loaded ram\n"); 113 | lcd_restore(savefile); 114 | io_restore(savefile); 115 | keypad_restore(savefile); 116 | mmap_restore(savefile); 117 | int_restore(savefile); 118 | rtc_restore(savefile); 119 | timer_restore(savefile); 120 | //printf("Loaded peripherals\n"); 121 | 122 | //printf("zpc %04x\n", zpc); 123 | ZCpu.Z80PC = (uintptr_t)cpu_rebasePC(zpc); 124 | //printf("rebased=%08x\n", ZCpu.Z80PC); 125 | 126 | fclose(savefile); 127 | } 128 | -------------------------------------------------------------------------------- /src/savestate.h: -------------------------------------------------------------------------------- 1 | void savestate_save(char *romfn); 2 | void savestate_load(char *savefn, char *romfn_p); 3 | -------------------------------------------------------------------------------- /src/speedcontrol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "timer.h" 5 | 6 | #define TICKS 0xffff 7 | 8 | struct timer { 9 | uint32_t load; 10 | uint32_t value; 11 | uint32_t control; 12 | uint32_t intclr; 13 | uint32_t ris; 14 | uint32_t mis; 15 | uint32_t bgload; 16 | }; 17 | 18 | struct timer_bkp { 19 | uint32_t load; 20 | uint32_t value; 21 | uint32_t control; 22 | }; 23 | 24 | volatile struct timer *timer1 = (struct timer *)0x900C0000; 25 | //volatile struct timer *timer1_2 = (struct timer *)0x900C0020; 26 | unsigned cycs_elapsed; 27 | struct timer_bkp tb; 28 | struct timer_bkp tb_2; 29 | 30 | volatile unsigned timer_flag = 0; 31 | 32 | void speedcontrol_init() { 33 | tb = *((struct timer_bkp *)&timer1); 34 | //tb_2 = *((struct timer_bkp *)&timer1_2); 35 | //timer1->load = TICKS; 36 | //timer1->value = 0; 37 | timer1->control = 0; 38 | //timer1_2->control = 0; 39 | 40 | //timer1->value = 0xffffffff; 41 | //timer1->control = 0b10000000; 42 | } 43 | 44 | void speedcontrol_end() { 45 | *((struct timer_bkp *)&timer1) = tb; 46 | // *((struct timer_bkp *)&timer1_2) = tb_2; 47 | } 48 | 49 | void speedcontrol_before() { 50 | timer1->control = 0b00000000; 51 | timer1->load = TICKS; 52 | timer1->control = 0b10000000; 53 | } 54 | 55 | void speedcontrol_after(int cycs_elapsed) { 56 | //cycs_elapsed += cycs; 57 | unsigned v = timer1->value & 0xffff; 58 | uint32_t elapsed = TICKS - v; 59 | int z80_32k_cycs = cycs_elapsed * 32768 / (cpu_freq_get() ? 15000000 : 6000000); 60 | //printf("%u %d %ld\n", v, z80_32k_cycs, elapsed); 61 | int new_cycs = z80_32k_cycs - elapsed; 62 | 63 | if(new_cycs > 0){ 64 | //printf("elapsed=%ld\n", elapsed); 65 | //printf("32k=%d\n", z80_32k_cycs); 66 | //printf("nc=%d\n", new_cycs); 67 | timer1->control = 0b00100001; 68 | timer1->load = new_cycs; 69 | timer1->control = 0b10100001; 70 | //puts("bb"); 71 | while(!timer_flag) { 72 | asm volatile("mcr p15, 0, %0, c7, c0, 4\n\t" : : "r"(0)); // WFI 73 | } 74 | //puts("cc"); 75 | timer1->control = 0; 76 | timer_flag = 0; 77 | //puts("dd"); 78 | } else { 79 | timer1->control = 0; 80 | } 81 | } 82 | 83 | void speedcontrol_int() { 84 | //puts("speedcontrol_int"); 85 | timer1->intclr = 0; 86 | //timer1->control = 0; 87 | //*(uint32_t *)0x900A0018 = 0b111111; 88 | timer_flag = 1; 89 | } -------------------------------------------------------------------------------- /src/speedcontrol.h: -------------------------------------------------------------------------------- 1 | void speedcontrol_init(); 2 | void speedcontrol_end(); 3 | void speedcontrol_before(); 4 | void speedcontrol_after(int cycs); 5 | 6 | void speedcontrol_int(); -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | #include "z_interrupt.h" 2 | #include "drz80.h" 3 | #include "util.h" 4 | #include 5 | extern struct DrZ80 ZCpu; 6 | 7 | struct timer_state { 8 | uint8_t cpu_freq; 9 | uint8_t timer_freq; 10 | uint8_t timers_enabled; 11 | }; 12 | 13 | struct timer_state ts = {0, 3, 0}; 14 | 15 | struct hwtimer { 16 | int tstates_left; 17 | uint8_t enabled; 18 | }; 19 | 20 | void timer_enable(struct hwtimer *t); 21 | void timer_disable(struct hwtimer *t); 22 | 23 | struct hwtimer timers[2] = {0}; 24 | 25 | uint16_t timer_cycles[2][4][3] = { // cpu speed, timer speed, timers enabled 26 | { 27 | {326, 163, 109}, 28 | {732, 366, 244}, 29 | {1139, 570, 380}, 30 | {1546, 773, 515}, 31 | }, 32 | { 33 | {130, 65, 43}, 34 | {293, 146, 98}, 35 | {456, 228, 152}, 36 | {618, 309, 206}, 37 | } 38 | }; 39 | 40 | int next_timer(){ 41 | int x = 32768/(64+(80*(ts.timer_freq))) * ts.timers_enabled; 42 | return (ts.cpu_freq ? 15000000 : 6000000) / x; 43 | //return timer_cycles[ts.cpu_freq][ts.timer_freq][ts.timers_enabled-1];// >> 2; 44 | } 45 | 46 | void timer_set_enabled(uint8_t mask){ 47 | int i; 48 | uint8_t ote = ts.timers_enabled; 49 | ts.timers_enabled = mask; 50 | for(i = 0; i < 2; i++){ 51 | if((mask & 1<enabled = 1; 58 | t->tstates_left = next_timer(); 59 | } 60 | 61 | void timer_disable(struct hwtimer *t){ 62 | t->tstates_left = 0; 63 | t->enabled = 0; 64 | } 65 | 66 | void timer_freq_set(uint8_t val){ 67 | ts.timer_freq = val; 68 | } 69 | 70 | 71 | int timer_after(int elapsed){ 72 | //printf("E %d\n", elapsed); 73 | int i; 74 | for(i = 0; i < 2; i++){ 75 | struct hwtimer *t = &timers[i]; 76 | if(!t->enabled) continue; 77 | t->tstates_left -= elapsed; 78 | //if(i == 0)printf("%d %d\n", t->tstates_left, elapsed); 79 | if(t->tstates_left <= 0){ 80 | //printf("timer %d fire\n", i); 81 | int_fire(1<<(i+1)); 82 | t->tstates_left += next_timer(); 83 | } 84 | } 85 | 86 | int tst_left = 10000;//INT_MAX; 87 | for(i = 0; i < 2; i++){ 88 | struct hwtimer *t = &timers[i]; 89 | if(t->enabled && t->tstates_left < tst_left) tst_left = t->tstates_left; 90 | } 91 | 92 | return tst_left; 93 | } 94 | 95 | void cpu_freq_set(uint8_t val){ 96 | ts.cpu_freq = val & 1; 97 | } 98 | uint8_t cpu_freq_get(){ 99 | return ts.cpu_freq; 100 | } 101 | 102 | void timer_save(FILE *f) { 103 | //FWRITE_VALUE(timers, f); 104 | FWRITE_VALUE(ts, f); 105 | fwrite(timers, sizeof(timers), 1, f); 106 | } 107 | 108 | void timer_restore(FILE *f) { 109 | FREAD_VALUE(&ts, f); 110 | fread(timers, sizeof(timers), 1, f); 111 | //FREAD_VALUE(&timers, f); 112 | } -------------------------------------------------------------------------------- /src/timer.h: -------------------------------------------------------------------------------- 1 | void timer_freq_set(uint8_t val); 2 | void cpu_freq_set(uint8_t val); 3 | uint8_t cpu_freq_get(); 4 | int next_timer(); 5 | int timer_after(int tstates_left); 6 | void timer_set_enabled(uint8_t mask); 7 | 8 | void timer_save(FILE *f); 9 | void timer_restore(FILE *f); -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define FWRITE_VALUE(x, file) assert(fwrite(&(x), sizeof(x), 1, file) == 1) 6 | #define FREAD_VALUE(x, file) assert(fread(x, sizeof(*(x)), 1, file) == 1) -------------------------------------------------------------------------------- /src/z_interrupt.c: -------------------------------------------------------------------------------- 1 | #include "z_interrupt.h" 2 | #include "timer.h" 3 | #include 4 | 5 | extern struct DrZ80 ZCpu; 6 | struct z_interrupt_state { 7 | uint8_t ints_enabled; 8 | uint8_t ints_firing; 9 | }; 10 | 11 | bool is_on_pressed() { 12 | return !((*(uint32_t *)0x900B0028) & (1<<4)); 13 | } 14 | 15 | struct z_interrupt_state zis = {0, 0}; 16 | 17 | void int_mask_out(uint8_t val){ 18 | //printf("int_mask_out %02x (f %02x)\n", val, zis.ints_firing); 19 | zis.ints_enabled = val; 20 | timer_set_enabled((val >> 1) & 0b11); 21 | zis.ints_firing &= val; 22 | /*if(val & INT_ON) printf("on "); 23 | if(val & INT_ON) printf("hwt1 "); 24 | if(val & INT_ON) printf("hwt2 "); 25 | if(val & INT_ON) printf("link "); 26 | if(val & INT_ON) printf("ct1 "); 27 | if(val & INT_ON) printf("ct2 "); 28 | if(val & INT_ON) printf("ct3 "); 29 | printf("\n");*/ 30 | } 31 | 32 | uint8_t int_mask_in(){ 33 | return zis.ints_enabled & ~(1<<3); 34 | } 35 | 36 | void int_ack_out(uint8_t val){ 37 | //printf("int_ack_out %02x\n", val); 38 | zis.ints_firing &= val; 39 | } 40 | 41 | uint8_t int_id_in(){ 42 | //printf("int_id_in %02x\n", zis.ints_firing); 43 | return zis.ints_firing | (is_on_pressed() ? 0 : 1<<3); 44 | } 45 | 46 | void int_fire(uint8_t num){ 47 | zis.ints_firing |= num; 48 | ZCpu.Z80_IRQ = 1; 49 | } 50 | 51 | void int_callback(){ 52 | ZCpu.Z80_IRQ = 0; 53 | /*if(zis.ints_firing != 0){ 54 | int_fire(zis.ints_firing); 55 | }*/ 56 | } 57 | 58 | void int_save(FILE *f){ 59 | FWRITE_VALUE(zis, f); 60 | } 61 | 62 | void int_restore(FILE *f){ 63 | FREAD_VALUE(&zis, f); 64 | } 65 | -------------------------------------------------------------------------------- /src/z_interrupt.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "drz80.h" 3 | #include "util.h" 4 | 5 | #define INT_ON 1<<0 6 | #define INT_HW1 1<<1 7 | #define INT_HW2 1<<2 8 | #define INT_LINK 1<<4 9 | #define INT_CT1 1<<5 10 | #define INT_CT2 1<<6 11 | #define INT_CT3 1<<7 12 | 13 | void int_mask_out(uint8_t val); 14 | uint8_t int_mask_in(); 15 | void int_ack_out(uint8_t val); 16 | uint8_t int_id_in(); 17 | void int_fire(uint8_t num); 18 | void int_callback(); 19 | 20 | bool is_on_pressed(); 21 | 22 | void int_save(FILE *f); 23 | void int_restore(FILE *f); --------------------------------------------------------------------------------