# HG changeset patch # User Michael Pavone # Date 1446841179 28800 # Node ID 69a6ec208111403475267462add0af9ee03e823e # Parent 305c85c0b954bb59951a977e57bec9e9771c4483 Menu ROM now pulls real file names from the OS rather than using a fake list diff -r 305c85c0b954 -r 69a6ec208111 Makefile --- a/Makefile Fri Nov 06 11:44:51 2015 -0800 +++ b/Makefile Fri Nov 06 12:19:39 2015 -0800 @@ -107,7 +107,7 @@ AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o -MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) +MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) CFLAGS+=-DX86_64 -m64 diff -r 305c85c0b954 -r 69a6ec208111 blastem.h --- a/blastem.h Fri Nov 06 11:44:51 2015 -0800 +++ b/blastem.h Fri Nov 06 12:19:39 2015 -0800 @@ -24,6 +24,7 @@ psg_context *psg; uint16_t *work_ram; uint8_t *zram; + void *extra; uint8_t *save_storage; eeprom_map *eeprom_map; uint32_t num_eeprom; diff -r 305c85c0b954 -r 69a6ec208111 config.c --- a/config.c Fri Nov 06 11:44:51 2015 -0800 +++ b/config.c Fri Nov 06 12:19:39 2015 -0800 @@ -43,7 +43,7 @@ config_data = started ? NULL : *state; while ((curline = strtok_r(config_data, "\n", state))) { - + config_data = NULL; curline = strip_ws(curline); int len = strlen(curline); @@ -61,7 +61,7 @@ } fatal_error("unexpected } on line %d\n", *line); } - + char * end = curline + len - 1; if (*end == '{') { *end = 0; @@ -128,7 +128,7 @@ if (!config_size) { goto config_empty; } - + char * config_data = malloc(config_size+1); if (SDL_RWread(rw, config_data, 1, config_size) != config_size) { goto config_read_fail; @@ -152,12 +152,12 @@ if (ret) { return ret; } - + ret = parse_config_file_assets("default.cfg"); if (ret) { return ret; } - + fatal_error("Failed to find a config file in internal storage or in the blastem APK\n"); //this will never get reached, but the compiler doesn't know that. Let's make it happy return NULL; @@ -169,25 +169,26 @@ { char * exe_dir; char * home = get_home_dir(); - if (home) { + tern_node *ret; + if (home) { char * path = alloc_concat(home, "/.config/blastem/blastem.cfg"); - tern_node * ret = parse_config_file(path); - free(path); - if (ret) { - return ret; - } - } - - exe_dir = get_exe_dir(); - if (exe_dir) { - path = alloc_concat(exe_dir, "/default.cfg"); ret = parse_config_file(path); free(path); if (ret) { return ret; } } - + + exe_dir = get_exe_dir(); + if (exe_dir) { + char *path = alloc_concat(exe_dir, "/default.cfg"); + ret = parse_config_file(path); + free(path); + if (ret) { + return ret; + } + } + fatal_error("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n"); //this will never get reached, but the compiler doesn't know that. Let's make it happy return NULL; diff -r 305c85c0b954 -r 69a6ec208111 menu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/menu.c Fri Nov 06 12:19:39 2015 -0800 @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include "blastem.h" +#include "menu.h" +#include "backend.h" +#include "util.h" + + +uint16_t menu_read_w(uint32_t address, void * context) +{ + //This should return the status of the last request with 0 + //meaning either the request is complete or no request is pending + //in the current implementation, the operations happen instantly + //in emulated time so we can always return 0 + return 0; +} + +void * menu_write_w(uint32_t address, void * context, uint16_t value) +{ + m68k_context *m68k = context; + genesis_context *gen = m68k->system; + menu_context *menu = gen->extra; + if (!menu) { + gen->extra = menu = calloc(1, sizeof(menu_context)); + menu->curpath = strdup(get_home_dir()); + } + if (menu->state) { + uint32_t dst = menu->latch << 16 | value; + switch (address >> 2) + { + case 0: { + size_t num_entries; + dir_entry *entries = get_dir_list(menu->curpath, &num_entries); + for (size_t i = 0; i < num_entries; i++) + { + uint8_t *dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen); + if (!dest) { + break; + } + *(dest++) = entries[i].is_dir; + *(dest++) = 1; + dst += 2; + uint8_t term = 0; + for (char *cpos = entries[i].name; *cpos; cpos++) + { + dest[1] = *cpos; + dest[0] = cpos[1]; + if (cpos[1]) { + cpos++; + } else { + term = 1; + } + dst += 2; + if (!(dst & 0xFFFF)) { + //we may have walked off the end of a memory block, get a fresh native pointer + dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen); + if (!dest) { + break; + } + } else { + dest += 2; + } + } + if (!term) { + *(dest++) = 0; + *dest = 0; + dst += 2; + } + } + free_dir_list(entries, num_entries); + break; + } + default: + fprintf(stderr, "WARNING: write to undefined menu port %X\n", address); + } + menu->state = 0; + } else { + menu->latch = value; + menu->state = 1; + } + + return context; +} diff -r 305c85c0b954 -r 69a6ec208111 menu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/menu.h Fri Nov 06 12:19:39 2015 -0800 @@ -0,0 +1,18 @@ +/* + Copyright 2015 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#ifndef MENU_H_ +#define MENU_H_ +typedef struct { + char *curpath; + uint16_t latch; + uint16_t state; +} menu_context; + + +uint16_t menu_read_w(uint32_t address, void * context); +void * menu_write_w(uint32_t address, void * context, uint16_t value); + +#endif // MENU_H_ diff -r 305c85c0b954 -r 69a6ec208111 menu.s68 --- a/menu.s68 Fri Nov 06 11:44:51 2015 -0800 +++ b/menu.s68 Fri Nov 06 12:19:39 2015 -0800 @@ -84,7 +84,7 @@ dc.b "Menu " dc.b " " dc.b " " - dc.b "GM MK-00000-00", 0, 0 + dc.b "MP BlstMenu-00", 0, 0 dc.b " " dc.l $0, rom_end-1, $FF0000, $FFFFFF dc.b " " @@ -92,7 +92,7 @@ dc.b " " dc.b " " dc.b "JUE " - + ;register addresses VDP_DATA equ $C00000 VDP_CTRL equ $C00004 @@ -139,21 +139,21 @@ vdpreg macro dc.w (((\1) << 8) | $8000 | (\2)) endm - + ;Writes a normal VDP command to the control port ;\1 - VDP address ;\2 - Access type vdpaccess macro move.l #((\2) | (\1) << 16 & $3FFF0000 | (\1) >> 14 & 3), (a1) endm - + ;Writes a DMA command to the control port ;\1 - Destination address ;\2 - Destination type startdma macro move.l #(\2 | VDP_DMA_FLAG | (\1 << 16) & $3FFF0000 | (\1 >> 14) & 3), (a1) endm - + DMA_SRC_68K equ 0 DMA_SRC_VRAM equ $C0 DMA_SRC_FILL equ $80 @@ -162,14 +162,19 @@ move.l #($95009600 + (\1) << 15 & $FF0000 + (\1) >> 9 & $FF), (a1) move.w #($9700 + (\1) >> 17 & $7F | (\2)), (a1) endm - + +dir_buffer equ $100000 +menu_port equ $180000 + +MAX_DISPLAY equ 24 + rsset $FFFF8000 x_pos rs.w 1 base_cmd rs.l 1 sprite_list rs.l 160 num_sprites rs.b 1 last_pad rs.b 1 - + int_6: dmasrc sprite_list, DMA_SRC_68K ;set DMA length @@ -184,7 +189,7 @@ move.b d1, d0 move.l d0, (a1) startdma $C000, VDP_VRAM_WRITE - + lea PAD1_DATA, a2 move.b #$40, (a2) move.b (a2), d0 @@ -200,14 +205,14 @@ eor.b d0, d1 and.b d0, d1 move.b d0, (last_pad).w - + moveq #16, d2 btst #1, d1 bne down btst #0, d1 bne up rte - + down: add.w d2, (sprite_list).w add.w d2, (sprite_list+8).w @@ -216,11 +221,11 @@ sub.w d2, (sprite_list).w sub.w d2, (sprite_list+8).w rte - + int_4: empty_handler: rte - + initial_regs: @@ -241,13 +246,13 @@ start: lea $C00000, a0 lea $C00004, a1 - + moveq #(end_initial_regs-initial_regs-1), d0 lea initial_regs.w, a2 .regloop move.w (a2)+, (a1) dbra d0, .regloop - + vdpaccess $0, VDP_CRAM_WRITE move.w #$020, (a0) move.w #$EEE, (a0) @@ -277,43 +282,76 @@ ploop: move.l d0, (a0) dbra d1, ploop - + ;setup SAT ;;vdpaccess $C000, VDP_VRAM_WRITE - + lea sprite_list.w, a2 ;left arrow move.l #$01080501, (a2)+ move.l #$807F0086, (a2)+ - + ;right arrow move.l #$01080500, (a2)+ move.l #$887F01AA, (a2)+ move.b #2, num_sprites.w - + move.l #$40860002, d3 move.l d3, (a1) move.l d3, base_cmd.w - lea Message(pc), a6 + lea dir_buffer, a6 + lea menu_port, a2 + move.l a6, (a2) + +wait_complete: + tst.w (a2) + bne wait_complete + + moveq #MAX_DISPLAY-1, d7 +file_loop: + tst.b (a6)+ + addq #1, a6 ;TODO: Do something with directory flag + + cmp.b #$2E, (a6) + bne normal + cmp.b #$2E, (1, a6) + beq normal + addq #1, a6 +.skip_loop: + tst.b (a6)+ + bne .skip_loop + addq #1, d7 + move.l a6, d6 + bra skip +normal: moveq #0, d0 bsr print_string - + move.l a6, d6 + + lea Newline(pc), a6 + bsr print_string + +skip: + ;word align pointer + addq #1, d6 + and.w #$FFFE, d6 + move.l d6, a6 + + dbra d7, file_loop + ;setup gamepad in port 1 move.b #$40, PAD1_CTRL - + move.w #$8174, (a1) ;enable display, vertical interrupts, DMA - + wait_forever stop #2500 bra wait_forever -Message: - dc.b "Journey From Darkness - Strider Returns (U) [c][!].bin", $A - dc.b "Toejam & Earl in Panic on Funkotron (U) [!].bin", $A - dc.b "Fire Shark (U) [c][!].bin", $A - dc.b "Sonic and Knuckles (W) [!].bin", 0 +Newline: + dc.b $A, 0 align 1 @@ -378,5 +416,5 @@ dc.b 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 dc.b 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 dc.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 - + rom_end: diff -r 305c85c0b954 -r 69a6ec208111 rom.db --- a/rom.db Fri Nov 06 11:44:51 2015 -0800 +++ b/rom.db Fri Nov 06 12:19:39 2015 -0800 @@ -353,4 +353,21 @@ offset 80000 } } -} \ No newline at end of file +} +BlstMenu { + map { + 0 { + device ROM + last FFFFF + } + 100000 { + device RAM + size 80000 + last 17FFFF + } + 180000 { + device MENU + last 1FFFFF + } + } +} diff -r 305c85c0b954 -r 69a6ec208111 romdb.c --- a/romdb.c Fri Nov 06 11:44:51 2015 -0800 +++ b/romdb.c Fri Nov 06 12:19:39 2015 -0800 @@ -4,6 +4,7 @@ #include "romdb.h" #include "util.h" #include "blastem.h" +#include "menu.h" #define TITLE_START 0x150 #define TITLE_END (TITLE_START+48) @@ -335,7 +336,7 @@ if (!map) { fatal_error("Could not find EEPROM map for address %X\n", address); } - + uint16_t expanded, mask; if (address & 1) { expanded = value; @@ -405,7 +406,7 @@ { uint8_t *last = rom + TITLE_END - 1; uint8_t *src = rom + TITLE_START; - + while (last > src && (*last <= 0x20 || *last >= 0x80)) { last--; @@ -490,24 +491,24 @@ } info->save_size = save_size; info->save_buffer = malloc(save_size); - + info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); memset(info->map, 0, sizeof(memmap_chunk)*2); memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks); - + if (ram_start >= rom_end) { info->map[0].end = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF; //TODO: ROM mirroring info->map[0].mask = 0xFFFFFF; info->map[0].flags = MMAP_READ; info->map[0].buffer = rom; - + info->map[1].start = ram_start; info->map[1].mask = info->save_mask; info->map[1].end = ram_end + 1; info->map[1].flags = MMAP_READ | MMAP_WRITE; - + if (ram_flags == RAM_FLAG_ODD) { info->map[1].flags |= MMAP_ONLY_ODD; } else if (ram_flags == RAM_FLAG_EVEN) { @@ -520,7 +521,7 @@ info->map[0].mask = 0xFFFFFF; info->map[0].flags = MMAP_READ; info->map[0].buffer = rom; - + info->map[1].start = 0x200000; info->map[1].end = 0x400000; info->map[1].mask = 0x1FFFFF; @@ -531,7 +532,7 @@ info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area info->map[1].write_8 = (write_8_fun)write_sram_area_b; info->map[1].buffer = cart + 0x200000; - + memmap_chunk *last = info->map + info->map_chunks - 1; memset(last, 0, sizeof(memmap_chunk)); last->start = 0xA13000; @@ -545,7 +546,7 @@ info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); memset(info->map, 0, sizeof(memmap_chunk)); memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks); - + info->map[0].end = rom_end > 0x400000 ? rom_end : 0x400000; info->map[0].mask = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF; info->map[0].flags = MMAP_READ; @@ -703,7 +704,7 @@ } else if (!strcmp(dtype, "EEPROM")) { process_eeprom_def(key, state); add_eeprom_map(node, start, end, state); - + map->write_16 = write_eeprom_i2c_w; map->write_8 = write_eeprom_i2c_b; map->read_16 = read_eeprom_i2c_w; @@ -719,6 +720,22 @@ map->flags |= MMAP_ONLY_EVEN; } map->mask = calc_mask(state->info->save_size, start, end); + } else if (!strcmp(dtype, "RAM")) { + uint32_t size = strtol(tern_find_ptr_default(node, "size", "0"), NULL, 16); + if (!size || size > map->end - map->start) { + size = map->end - map->start; + } + map->buffer = malloc(size); + map->mask = calc_mask(size, start, end); + map->flags = MMAP_READ | MMAP_WRITE; + char *bus = tern_find_ptr_default(node, "bus", "both"); + if (!strcmp(dtype, "odd")) { + map->flags |= MMAP_ONLY_ODD; + } else if (!strcmp(dtype, "even")) { + map->flags |= MMAP_ONLY_EVEN; + } else { + map->flags |= MMAP_CODE; + } } else if (!strcmp(dtype, "Sega mapper")) { state->info->mapper_start_index = state->ptr_index++; state->info->map_chunks+=7; @@ -760,6 +777,12 @@ map->mask = 0xFF; map->write_16 = (write_16_fun)write_bank_reg_w; map->write_8 = (write_8_fun)write_bank_reg_b; + } else if (!strcmp(dtype, "MENU")) { + //fake hardware for supporting menu + map->buffer = NULL; + map->mask = 0xFF; + map->write_16 = menu_write_w; + map->read_16 = menu_read_w; } else { fatal_error("Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); } @@ -778,7 +801,7 @@ break; } product_id[i] = rom[GAME_ID_OFF + i]; - + } printf("Product ID: %s\n", product_id); tern_node * entry = tern_find_ptr(rom_db, product_id); @@ -794,7 +817,7 @@ } else { info.name = get_header_name(rom); } - + char *dbreg = tern_find_ptr(entry, "regions"); info.regions = 0; if (dbreg) { @@ -806,7 +829,7 @@ if (!info.regions) { info.regions = get_header_regions(rom); } - + tern_node *map = tern_find_ptr(entry, "map"); if (map) { info.save_type = SAVE_NONE; @@ -828,6 +851,6 @@ } else { add_memmap_header(&info, rom, rom_size, base_map, base_chunks); } - + return info; } diff -r 305c85c0b954 -r 69a6ec208111 util.c --- a/util.c Fri Nov 06 11:44:51 2015 -0800 +++ b/util.c Fri Nov 06 12:19:39 2015 -0800 @@ -11,6 +11,7 @@ #include "blastem.h" //for headless global #include "render.h" //for render_errorbox +#include "util.h" char * alloc_concat(char * first, char * second) { @@ -277,5 +278,46 @@ } return exe_dir; } +#include + +dir_entry *get_dir_list(char *path, size_t *numret) +{ + DIR *d = opendir(path); + if (!d) { + if (numret) { + *numret = 0; + } + return NULL; + } + size_t storage = 64; + dir_entry *ret = malloc(sizeof(dir_entry) * storage); + size_t pos = 0; + struct dirent* entry; + while (entry = readdir(d)) + { + if (entry->d_type != DT_REG && entry->d_type != DT_LNK && entry->d_type != DT_DIR) { + continue; + } + if (pos == storage) { + storage = storage * 2; + ret = realloc(ret, sizeof(dir_entry) * storage); + } + ret[pos].name = strdup(entry->d_name); + ret[pos++].is_dir = entry->d_type == DT_DIR; + } + if (numret) { + *numret = pos; + } + return ret; +} + +void free_dir_list(dir_entry *list, size_t numentries) +{ + for (size_t i = 0; i < numentries; i++) + { + free(list[i].name); + } + free(list); +} #endif diff -r 305c85c0b954 -r 69a6ec208111 util.h --- a/util.h Fri Nov 06 11:44:51 2015 -0800 +++ b/util.h Fri Nov 06 12:19:39 2015 -0800 @@ -3,6 +3,11 @@ #include +typedef struct { + char *name; + uint8_t is_dir; +} dir_entry; + //Utility functions //Allocates a new string containing the concatenation of first and second @@ -23,6 +28,10 @@ char * get_exe_dir(); //Returns the user's home directory char * get_home_dir(); +//Retunrs an array of normal files and directories residing in a directory +dir_entry *get_dir_list(char *path, size_t *numret); +//Frees a dir list returned by get_dir_list +void free_dir_list(dir_entry *list, size_t numentries); //Returns the contents of a symlink in a newly allocated string char * readlink_alloc(char * path); //Prints an error message to stderr and to a message box if not in headless mode and then exits