197 lines
4.7 KiB
C
197 lines
4.7 KiB
C
/*
|
|
* 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 <stdlib.h>
|
|
|
|
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;
|
|
}
|