Add mbc2
This commit is contained in:
		
							parent
							
								
									fb0d9a9cc4
								
							
						
					
					
						commit
						8731b45567
					
				|  | @ -28,5 +28,6 @@ void gb_timers_update(GBTimers *timers, ut32 cycles); | ||||||
| 
 | 
 | ||||||
| extern RIOPlugin r_io_plugin_gb_timers; | extern RIOPlugin r_io_plugin_gb_timers; | ||||||
| extern RIOPlugin r_io_plugin_gb_mbc1; | extern RIOPlugin r_io_plugin_gb_mbc1; | ||||||
|  | extern RIOPlugin r_io_plugin_gb_mbc2; | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								io/mbc1.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								io/mbc1.c
									
									
									
									
									
								
							|  | @ -3,6 +3,10 @@ | ||||||
| #include <r_io.h> | #include <r_io.h> | ||||||
| #include <r_util.h> | #include <r_util.h> | ||||||
| 
 | 
 | ||||||
|  | #ifndef GB_H | ||||||
|  | RIOPlugin r_io_plugin_gb_mbc1; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| typedef struct gb_mbc1_data { | typedef struct gb_mbc1_data { | ||||||
| 	RIO *io; | 	RIO *io; | ||||||
| 	ut32 *rombank_to_io_map; | 	ut32 *rombank_to_io_map; | ||||||
|  | @ -110,6 +114,9 @@ static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { | ||||||
| 	} | 	} | ||||||
| 	mbc->io->va = true; | 	mbc->io->va = true; | ||||||
| 	mbc->file_fd = r_io_fd_open (mbc->io, &pathname[10], R_PERM_R, 0); | 	mbc->file_fd = r_io_fd_open (mbc->io, &pathname[10], R_PERM_R, 0); | ||||||
|  | 	if (mbc->file_fd < 0) { | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
| 	if (mbc->n_rambanks) { | 	if (mbc->n_rambanks) { | ||||||
| 		char *malloc_uri = r_str_newf ("malloc://0x%"PFMT64x,  | 		char *malloc_uri = r_str_newf ("malloc://0x%"PFMT64x,  | ||||||
| 			mbc->small_ram? 0x800: (0x2000 * mbc->n_rambanks)); | 			mbc->small_ram? 0x800: (0x2000 * mbc->n_rambanks)); | ||||||
|  | @ -119,9 +126,6 @@ static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { | ||||||
| 			goto fail; | 			goto fail; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (mbc->file_fd < 0) { |  | ||||||
| 		goto fail; |  | ||||||
| 	} |  | ||||||
| 	RIOMap *map; | 	RIOMap *map; | ||||||
| 	ut32 i; | 	ut32 i; | ||||||
| 	for (i = 0; i < mbc->n_rombanks; i++) { | 	for (i = 0; i < mbc->n_rombanks; i++) { | ||||||
|  |  | ||||||
							
								
								
									
										281
									
								
								io/mbc2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								io/mbc2.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,281 @@ | ||||||
|  | #include <stdio.h> | ||||||
|  | //#include <gb.h>
 | ||||||
|  | #include <r_io.h> | ||||||
|  | #include <r_util.h> | ||||||
|  | 
 | ||||||
|  | typedef struct gb_mbc2_ram_data { | ||||||
|  | 	ut64 seek; | ||||||
|  | 	ut8 buf[512]; | ||||||
|  | } MBC2Ram; | ||||||
|  | 
 | ||||||
|  | RIOPlugin r_io_plugin_gb_mbc2_ram; | ||||||
|  | #ifndef GB_H | ||||||
|  | RIOPlugin r_io_plugin_gb_mbc2; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static bool __ram_check(RIO *io, const char *pathname, bool many) { | ||||||
|  | 	return r_str_startswith (pathname, "gb_mbc2_ram://"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static RIODesc *__ram_open(RIO *io, const char *pathname, int rw, int mode) { | ||||||
|  | 	if (!r_str_startswith (pathname, "gb_mbc2_ram://")) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	MBC2Ram *ram = R_NEW0 (MBC2Ram); | ||||||
|  | 	if (!ram) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	RIODesc *desc = r_io_desc_new (io, &r_io_plugin_gb_mbc2_ram, pathname, | ||||||
|  | 		R_PERM_RWX, mode, ram); | ||||||
|  | 	if (!desc) { | ||||||
|  | 		free (ram); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	memset (ram->buf, 0xf0, 512 * sizeof (ut8)); | ||||||
|  | 	return desc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool __ram_close(RIODesc *desc) { | ||||||
|  | 	free (desc->data); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ut64 __ram_lseek(RIO* io, RIODesc *desc, ut64 offset, int whence) { | ||||||
|  | 	MBC2Ram *ram = (MBC2Ram *)desc->data; | ||||||
|  | 	switch (whence) { | ||||||
|  | 	case R_IO_SEEK_SET: | ||||||
|  | 		return ram->seek = R_MIN (0x200, offset); | ||||||
|  | 	case R_IO_SEEK_CUR: | ||||||
|  | 		return ram->seek = R_MIN (0x200, ram->seek + offset); | ||||||
|  | 	case R_IO_SEEK_END: | ||||||
|  | 		return ram->seek = 0x200; | ||||||
|  | 	} | ||||||
|  | 	return ram->seek; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int __ram_read(RIO *io, RIODesc *desc, ut8 *buf, int len) { | ||||||
|  | 	MBC2Ram *ram = (MBC2Ram *)desc->data; | ||||||
|  | 	len = R_MIN (len, 0x200 - ram->seek); | ||||||
|  | 	if (len < 0) { | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	memcpy (buf, &ram->buf[ram->seek], len); | ||||||
|  | 	ram->seek += len; | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int __ram_write(RIO *io, RIODesc *desc, const ut8 *buf, int len) { | ||||||
|  | 	MBC2Ram *ram = (MBC2Ram *)desc->data; | ||||||
|  | 	const int ret = len = R_MIN (len, 0x200 - ram->seek); | ||||||
|  | 	if (len < 0) { | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	memcpy (&ram->buf[ram->seek], buf, len); | ||||||
|  | 	if (R_UNLIKELY (len > 7)) { | ||||||
|  | 		ut32 ut64len = len >> 3; | ||||||
|  | 		do { | ||||||
|  | 			ut64 *buf64 = (ut64 *)(&ram->buf[ram->seek]); | ||||||
|  | 			*buf64 |= 0xf0f0f0f0f0f0f0f0; | ||||||
|  | 			ram->seek += 8; | ||||||
|  | 		} while (--ut64len); | ||||||
|  | 		len &= 7; | ||||||
|  | 	} | ||||||
|  | 	do { | ||||||
|  | 		ram->buf[ram->seek] |= 0xf0; | ||||||
|  | 		ram->seek++; | ||||||
|  | 	} while (--len); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RIOPlugin r_io_plugin_gb_mbc2_ram = { | ||||||
|  | 	.meta = { | ||||||
|  | 		.name = "gb_mbc2_ram", | ||||||
|  | 		.desc = "gb_mbc2_ram", | ||||||
|  | 		.license = "LGPL", | ||||||
|  | 	}, | ||||||
|  | 	.uris = "gb_mbc2_ram://", | ||||||
|  | 	.open = __ram_open, | ||||||
|  | 	.close = __ram_close, | ||||||
|  | 	.read = __ram_read, | ||||||
|  | 	.check = __ram_check, | ||||||
|  | 	.seek = __ram_lseek, | ||||||
|  | 	.write = __ram_write, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct gb_mbc2_data { | ||||||
|  | 	RIO *io; | ||||||
|  | 	RIODesc *mem_desc; | ||||||
|  | 	ut32 rombank_to_io_map[16]; | ||||||
|  | 	ut64 seek; | ||||||
|  | 	int file_fd; | ||||||
|  | 	ut8 rombank; | ||||||
|  | 	bool ram_enable; | ||||||
|  | } MBC2; | ||||||
|  | 
 | ||||||
|  | static void disable_ram (MBC2 *mbc) { | ||||||
|  | 	mbc->mem_desc->perm = 0; | ||||||
|  | 	mbc->ram_enable = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void enable_ram (MBC2 *mbc) { | ||||||
|  | 	mbc->mem_desc->perm = R_PERM_RW; | ||||||
|  | 	mbc->ram_enable = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool __check(RIO *io, const char *pathname, bool many) { | ||||||
|  | 	return r_str_startswith (pathname, "gb_mbc2://"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { | ||||||
|  | 	if (!r_str_startswith (pathname, "gb_mbc2://")) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	if (!r_file_exists (&pathname[10]) || !r_file_is_regular (&pathname[10])) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	RIODesc *desc = r_io_desc_open (io, &pathname[10], R_PERM_R, 0); | ||||||
|  | 	if (!desc) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	ut8 mbc_info = 0xfb; | ||||||
|  | 	r_io_desc_read_at (desc, 0x147, &mbc_info, 1); | ||||||
|  | 	r_io_desc_close (desc); | ||||||
|  | 	if (R_UNLIKELY (mbc_info != 0x5 || mbc_info != 0x6)) { | ||||||
|  | 		//not a mbc2 rom
 | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	MBC2 *mbc = R_NEW0 (MBC2); | ||||||
|  | 	if (!mbc) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	mbc->io = r_io_new (); | ||||||
|  | 	if (!mbc->io) { | ||||||
|  | 		free (mbc); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	mbc->io->va = true; | ||||||
|  | 	mbc->file_fd = r_io_fd_open (mbc->io, &pathname[10], R_PERM_R, 0); | ||||||
|  | 	if (mbc->file_fd < 0) { | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 	mbc->mem_desc = r_io_desc_open_plugin (mbc->io, &r_io_plugin_gb_mbc2_ram, "gb_mbc2_ram://", | ||||||
|  | 		R_PERM_RW, 0); | ||||||
|  | 	if (!mbc->mem_desc) { | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 	RIOMap *map = r_io_map_add (mbc->io, mbc->file_fd, R_PERM_R, 0ULL, 0ULL, 0x4000); | ||||||
|  | 	mbc->rombank_to_io_map[0] = map->id; | ||||||
|  | 	if (R_UNLIKELY (!r_io_map_add (mbc->io, mbc->mem_desc->fd, R_PERM_RW, 0ULL, | ||||||
|  | 		0xa000, 0x200))) { | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 	ut32 i; | ||||||
|  | 	for (i = 1; i < 16; i++) { | ||||||
|  | 		map = r_io_map_add_bottom (mbc->io, mbc->file_fd, R_PERM_R, | ||||||
|  | 			0x4000 * i, 0x4000, 0x4000); | ||||||
|  | 		if (R_UNLIKELY (!map)) { | ||||||
|  | 			goto fail; | ||||||
|  | 		} | ||||||
|  | 		if (R_UNLIKELY (!r_io_map_add (mbc->io, mbc->mem_desc->fd, R_PERM_RW, | ||||||
|  | 			0ULL, 0xa000 + i * 0x200, 0x200))) { | ||||||
|  | 			goto fail; | ||||||
|  | 		} | ||||||
|  | 		mbc->rombank_to_io_map[i] = map->id; | ||||||
|  | 	} | ||||||
|  | 	mbc->io->cache.mode = 0; | ||||||
|  | 	desc = r_io_desc_new (io, &r_io_plugin_gb_mbc2, pathname, R_PERM_RWX, mode, mbc); | ||||||
|  | 	if (!desc) { | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 	mbc->io->va = true; | ||||||
|  | 	mbc->rombank = 1; | ||||||
|  | 	disable_ram (mbc); | ||||||
|  | 	return desc; | ||||||
|  | fail: | ||||||
|  | 	r_io_free (mbc->io); | ||||||
|  | 	free (mbc); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool __close(RIODesc *desc) { | ||||||
|  | 	MBC2 *mbc = (MBC2 *)desc->data; | ||||||
|  | 	r_io_free (mbc->io); | ||||||
|  | 	R_FREE (desc->data); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ut64 __lseek(RIO* io, RIODesc *desc, ut64 offset, int whence) { | ||||||
|  | 	MBC2 *mbc = (MBC2 *)desc->data; | ||||||
|  | 	switch (whence) { | ||||||
|  | 	case R_IO_SEEK_SET: | ||||||
|  | 		return mbc->seek = R_MIN (0xc000, offset); | ||||||
|  | 	case R_IO_SEEK_CUR: | ||||||
|  | 		return mbc->seek = R_MIN (0xc000, mbc->seek + offset); | ||||||
|  | 	case R_IO_SEEK_END: | ||||||
|  | 		return mbc->seek = 0xc000; | ||||||
|  | 	} | ||||||
|  | 	return mbc->seek; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int __write(RIO *io, RIODesc *desc, const ut8 *buf, int len) { | ||||||
|  | 	MBC2 *mbc = (MBC2 *)desc->data; | ||||||
|  | 	len = R_MIN (len, 0xc000 - mbc->seek); | ||||||
|  | 	r_io_write_at (mbc->io, mbc->seek, buf, len); | ||||||
|  | 	ut64 endseek = mbc->seek + len; | ||||||
|  | 	while ((mbc->seek < 0x4000) && (mbc->seek < endseek)) { | ||||||
|  | 		const ut32 i = mbc->seek - (endseek - len); | ||||||
|  | 		if (mbc->seek & 0x100) { | ||||||
|  | 			ut8 rombank = buf[i] & 0x0f; | ||||||
|  | 			if (!rombank) { | ||||||
|  | 				rombank++; | ||||||
|  | 			} | ||||||
|  | 			r_io_map_priorize (mbc->io, mbc->rombank_to_io_map[rombank]); | ||||||
|  | 			mbc->rombank = rombank; | ||||||
|  | 		} else { | ||||||
|  | 			if (buf[i] == 0x0a) { | ||||||
|  | 				enable_ram (mbc); | ||||||
|  | 			} else { | ||||||
|  | 				disable_ram (mbc); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		mbc->seek++; | ||||||
|  | 	} | ||||||
|  | 	mbc->seek = endseek; | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int __read(RIO *io, RIODesc *desc, ut8 *buf, int len) { | ||||||
|  | 	MBC2 *mbc = (MBC2 *)desc->data; | ||||||
|  | 	len = R_MIN (len, 0xc000 - mbc->seek); | ||||||
|  | 	if (!r_io_read_at (mbc->io, mbc->seek, buf, len)) { | ||||||
|  | 		eprintf ("r_io_read_at failed\n"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	eprintf ("read @ 0x%"PFMT64x" %d bytes\n", mbc->seek, len); | ||||||
|  | 	mbc->seek += len; | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RIOPlugin r_io_plugin_gb_mbc2 = { | ||||||
|  | 	.meta = { | ||||||
|  | 		.name = "gb_mbc2", | ||||||
|  | 		.desc = "gb_mbc2", | ||||||
|  | 		.license = "LGPL", | ||||||
|  | 	}, | ||||||
|  | 	.uris = "gb_mbc2://", | ||||||
|  | 	.open = __open, | ||||||
|  | 	.close = __close, | ||||||
|  | 	.read = __read, | ||||||
|  | 	.check = __check, | ||||||
|  | 	.seek = __lseek, | ||||||
|  | 	.write = __write, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #ifndef R2_PLUGIN_INCORE | ||||||
|  | R_API RLibStruct radare_plugin = { | ||||||
|  | 	.type = R_LIB_TYPE_IO, | ||||||
|  | 	.data = &r_io_plugin_gb_mbc2, | ||||||
|  | 	.version = R2_VERSION | ||||||
|  | }; | ||||||
|  | #endif | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user