Files
CDi_MiSTer/sim2/sim_top.cpp
Andre Zeps dc5cb2e735 Second video channel and mouse cursor
- Added ICA1 and FILE1
- CLUT implemented as True Dual-Port RAM to allow
  writing and reading with two video channels
- Added weight calculations
- Mouse cursor
2024-08-26 21:50:07 +02:00

305 lines
8.7 KiB
C++

// Include common routines
#include <verilated.h>
#include <verilated_vcd_c.h>
// Include model header, generated from Verilating "top.v"
#include "Vemu.h"
#include "Vemu___024root.h"
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <png.h>
#include "hle.h"
uint64_t sim_time = 0;
static bool do_trace{true};
volatile sig_atomic_t status = 0;
static void catch_function(int signo) {
status = signo;
}
const int width = 120 * 16;
const int height = 600;
const int size = width * height * 3;
uint8_t output_image[size] = {0};
void write_png_file(const char *filename) {
int y;
FILE *fp = fopen(filename, "wb");
if (!fp)
abort();
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png)
abort();
png_infop info = png_create_info_struct(png);
if (!info)
abort();
if (setjmp(png_jmpbuf(png)))
abort();
png_init_io(png, fp);
// Output is 8bit depth, RGBA format.
png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png, info);
png_bytepp row_pointers = (png_bytepp)png_malloc(png, sizeof(png_bytepp) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = &output_image[width * 3 * i];
}
png_write_image(png, row_pointers);
png_write_end(png, NULL);
free(row_pointers);
fclose(fp);
png_destroy_write_struct(&png, &info);
}
void clock(VerilatedVcdC &m_trace, Vemu &dut) {
for (int i = 0; i < 2; i++) {
dut.rootp->emu__DOT__clk_sys = (sim_time & 1);
dut.eval();
if (do_trace) {
m_trace.dump(sim_time);
}
sim_time++;
}
}
void loadfile(uint16_t index, const char *path, VerilatedVcdC &m_trace, Vemu &dut) {
FILE *f = fopen(path, "rb");
assert(f);
uint16_t transferword;
dut.rootp->emu__DOT__ioctl_addr = 0;
dut.rootp->emu__DOT__ioctl_index = index;
// make some clocks before starting
for (int y = 0; y < 300; y++) {
clock(m_trace, dut);
}
while (fread(&transferword, 2, 1, f) == 1) {
dut.rootp->emu__DOT__ioctl_wr = 1;
dut.rootp->emu__DOT__ioctl_dout = transferword;
clock(m_trace, dut);
dut.rootp->emu__DOT__ioctl_wr = 0;
// make some clocks to avoid asking for busy
// the real MiSTer has 31 clocks between writes
// we are going for ~20 to put more stress on it.
for (int i = 0; i < 20; i++) {
clock(m_trace, dut);
}
dut.rootp->emu__DOT__ioctl_addr += 2;
clock(m_trace, dut);
}
fclose(f);
}
void printstate(Vemu &dut) {
static uint32_t regfile[16];
uint32_t pc = dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__exe_pc;
// d0 = dut.rootp->fx68k_tb__DOT__d0;
memcpy(regfile, &dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__regfile[0],
sizeof(regfile));
printf("%x", pc);
for (int i = 0; i < 16; i++)
printf(" %x", regfile[i]);
printf("\n");
}
void do_justwait(VerilatedVcdC &m_trace, Vemu &dut) {
dut.eval();
do_trace = false;
dut.rootp->emu__DOT__debug_uart_fake_space = false;
/*
fread(&dut.rootp->emu__DOT__ram[0], 1, 1024 * 256, f);
fread(&dut.rootp->emu__DOT__ram[2 * 1024 * 128], 1, 1024 * 256, f);
fread(&dut.rootp->emu__DOT__ram[1 * 1024 * 128], 1, 1024 * 256, f);
fread(&dut.rootp->emu__DOT__ram[3 * 1024 * 128], 1, 1024 * 256, f);
*/
// 0x7FFB0 0xCD04 0xC1B9
dut.RESET = 1;
dut.UART_RXD = 1;
// wait for SDRAM to initialize
for (int y = 0; y < 300; y++) {
clock(m_trace, dut);
}
/*
dut.rootp->emu__DOT__ioctl_download = 1;
loadfile(0, "cdi200.rom", m_trace, dut);
loadfile(0x0040, "zx405042p__cdi_slave_2.0__b43t__zzmk9213.mc68hc705c8a_withtestrom.7206", m_trace, dut);
dut.rootp->emu__DOT__ioctl_download = 0;
*/
dut.RESET = 0;
// for (int y = 0; y < 780000; y++) {
for (int y = 0;; y++) {
clock(m_trace, dut);
if ((y % 100000) == 0) {
printf("%d\n", y);
}
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__trap_illegal) {
fprintf(stderr, "NOPE!\n");
break;
}
/*
if (y == 600000)
do_trace = true;
if (y == 700000)
break;
*/
/*
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__uart_transmit_holding_valid) {
fputc(dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__uart_transmit_holding_register, stderr);
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__uart_transmit_holding_valid = 0;
}
*/
static uint32_t print_instructions = 0;
static uint32_t prevpc = 0;
static uint32_t leave_sys_callpc = 0;
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__decodeopc &&
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__clkena_in) {
uint32_t m_pc = dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__exe_pc;
if (m_pc == 0x62c) {
assert((prevpc & 1) == 0);
uint32_t callpos = ((prevpc & 0x3fffff) >> 1) + 1;
uint32_t call = dut.rootp->emu__DOT__rom[callpos];
printf("Syscall %x %x %s\n", prevpc, call, systemCallNameToString(static_cast<SystemCallType>(call)));
leave_sys_callpc = prevpc + 4;
}
if (m_pc == leave_sys_callpc) {
printf("Return from Syscall %x %x\n",
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__flags,
dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__flagssr);
printstate(dut);
}
prevpc = m_pc;
}
if (dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__tg68__DOT__tg68kdotcinst__DOT__decodeopc &&
print_instructions && dut.rootp->emu__DOT__cditop__DOT__scc68070_0__DOT__clkena_in) {
printstate(dut);
// d1 = dut.rootp->fx68k_tb__DOT__d1;
/*
printf("%x %x %x %x %x %x\n", pc, dut.rootp->fx68k_tb__DOT__d0, dut.rootp->fx68k_tb__DOT__d1,
regfile[8 + 0], regfile[8 + 2], regfile[8 + 6]);
*/
}
static int output_index = 0;
static int frame_index = 0;
if (dut.rootp->emu__DOT__cditop__DOT__mcd212_inst__DOT__new_frame) {
char filename[100];
if (frame_index == 251) {
// dut.rootp->emu__DOT__cditop__DOT__mcd212_inst__DOT__file0__DOT__debug_print_file = 1;
}
if (output_index > 100) {
sprintf(filename, "video_%02d.png", frame_index);
write_png_file(filename);
printf("Written %s %d\n", filename, output_index);
fprintf(stderr, "Written %s\n", filename);
frame_index++;
}
output_index = 0;
}
if (output_index < size - 6) {
if (dut.VGA_DE) {
output_image[output_index++] = dut.VGA_R;
output_image[output_index++] = dut.VGA_G;
output_image[output_index++] = dut.VGA_B;
} else {
output_image[output_index++] = do_trace ? 80 : 10;
output_image[output_index++] = 10;
output_image[output_index++] = 10;
}
}
if (status == SIGINT)
break;
}
if (1) {
printf("Writing rampdump!\n");
FILE *f = fopen("slavedump.bin", "wb");
assert(f);
fwrite(&dut.rootp->emu__DOT__cditop__DOT__uc68hc05_0__DOT__memory[0], 1, 1024 * 8, f);
fclose(f);
}
// printf("ICA1 %x\n",dut.rootp->fx68k_tb__DOT__mcd212_inst__DOT__testram[ica1>>1]);
}
int main(int argc, char **argv) {
// Initialize Verilators variables
Verilated::commandArgs(argc, argv);
if (do_trace)
Verilated::traceEverOn(true);
VerilatedVcdC m_trace;
Vemu dut;
if (signal(SIGINT, catch_function) == SIG_ERR) {
fputs("An error occurred while setting a signal handler.\n", stderr);
return EXIT_FAILURE;
}
dut.trace(&m_trace, 5);
if (do_trace)
m_trace.open("/tmp/waveform.vcd");
// do_selftest_dram(m_trace, dut);
// do_selftest_lowlevelpcb(m_trace, dut);
// do_selftest_cdic(m_trace, dut);
// do_selftest_slave(m_trace, dut);
do_justwait(m_trace, dut);
fprintf(stderr, "Closing...\n");
fflush(stdout);
return 0;
}