/* * Copyright (c) 2002 - 2018 Magnus Lind. * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software, alter it and re- * distribute it freely for any non-commercial, non-profit purpose subject to * the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in a * product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any distribution. * * 4. The names of this software and/or it's copyright holders may not be * used to endorse or promote products derived from this software without * specific prior written permission. * */ #include "../src/log.h" #include "../src/exo_util.h" #include "../src/6502emu.h" #include "../src/areatrace.h" #include "../src/int.h" #include "../src/buf_io.h" #include "../src/perf.h" #include struct mem_ctx { u8 *mem; struct areatrace at; }; static void mem_access_write(struct mem_access *this, u16 address, u8 value) { struct mem_ctx *ctx = this->ctx; ctx->mem[address] = value; areatrace_access(&ctx->at, address); } static u8 mem_access_read(struct mem_access *this, u16 address) { struct mem_ctx *ctx = this->ctx; return ctx->mem[address]; } void save_single(const char *in_name, struct buf *mem, int start, int end) { struct buf mb_name; const char *out_name; buf_init(&mb_name); buf_printf(&mb_name, "%s.out", in_name); out_name = (const char *)buf_data(&mb_name); buf_remove(mem, end, -1); buf_remove(mem, 0, start); write_file(out_name, mem); buf_free(&mb_name); } void test_single(const char *prg_name, const char *data_name, int *cyclesp, int *in_lenp, int *out_lenp) { struct cpu_ctx r; struct load_info prg_info; struct load_info data_info; struct buf mem_mb; u8 *mem; struct mem_ctx mem_ctx; int start; int end; buf_init(&mem_mb); buf_append(&mem_mb, NULL, 65536); mem = buf_data(&mem_mb); memset(mem, 0, 65536); mem_ctx.mem = mem; areatrace_init(&mem_ctx.at); prg_info.basic_txt_start = 0x0801; data_info.basic_txt_start = 0x0801; load_located(prg_name, mem, &prg_info); /* no start address from load*/ if(prg_info.run == -1) { /* look for sys line */ prg_info.run = find_sys(mem + prg_info.basic_txt_start, 0x9e, NULL); } if(prg_info.run == -1) { LOG(LOG_ERROR, ("Error, can't find entry point.\n")); exit(-1); } LOG(LOG_DEBUG, ("run %04x\n", prg_info.run)); load_located(data_name, mem, &data_info); /* communicate the data region to the prg */ mem[2] = data_info.start & 255; mem[3] = data_info.start >> 8; mem[4] = data_info.end & 255; mem[5] = data_info.end >> 8; r.cycles = 0; r.mem.ctx = &mem_ctx; r.mem.read = mem_access_read; r.mem.write = mem_access_write; r.pc = prg_info.run; r.sp = '\xff'; r.flags = 0; /* setting up decrunch */ while(r.sp >= 0x10) { next_inst(&r); } /* save traced area */ areatrace_merge_overlapping(&mem_ctx.at); areatrace_get_largest(&mem_ctx.at, &start, &end); save_single(data_name, &mem_mb, start, end); areatrace_free(&mem_ctx.at); buf_free(&mem_mb); if (cyclesp != NULL) { *cyclesp = r.cycles; } if (in_lenp != NULL) { *in_lenp = data_info.end - data_info.start; } if (out_lenp != NULL) { *out_lenp = end - start; } } int main(int argc, char *argv[]) { struct perf_ctx perf; struct buf buf; int i; int cycles; int inlen; int outlen; int cycles_sum = 0; int inlen_sum = 0; int outlen_sum = 0; /* init logging */ LOG_INIT_CONSOLE(LOG_TERSE); perf_init(&perf); for (i = 1; i < argc; i += 2) { test_single(argv[i], argv[i + 1], &cycles, &inlen, &outlen); perf_add(&perf, argv[i + 1], inlen, outlen, cycles); cycles_sum += cycles; inlen_sum += inlen; outlen_sum += outlen; } if (argc > 3) { perf_add(&perf, "Total", inlen_sum, outlen_sum, cycles_sum); } buf_init(&buf); perf_buf_print(&perf, &buf); LOG(LOG_TERSE, ("%s", (char*)buf_data(&buf))); buf_free(&buf); perf_free(&perf); return 0; }