debug.c 7.09 KB
//
// Created by imanol on 12/26/16.
//

#include <malloc.h>
#include <string.h>
#include "debug.h"

//uint32_t cycle_count = 0;
uint8_t breakpoint = 1;
uint16_t breakpoints[0xFF];
uint16_t nbpoints = 0;
char lastchoice = 0;

void load_state(char *filename)
{
    FILE *state = fopen(filename,"r");
    uint16_t regsdump[NUM_REGISTERS+1];
    uint16_t memdump[MEMSIZE];
    uint16_t *stackdump;
    uint32_t stacksize, stackpos;
    
    fread(regsdump,sizeof(uint16_t),NUM_REGISTERS+1,state);
    fread(memdump,sizeof(uint16_t),MEMSIZE,state);
    stackpos = ftell(state);
    fseek(state,0,SEEK_END);
    stacksize = (ftell(state) - stackpos)/sizeof(uint16_t);
    stackdump = calloc(stacksize,sizeof(uint16_t));
    fseek(state,stackpos,SEEK_SET);
    fread(stackdump,sizeof(uint16_t),stacksize,state);
    fclose(state);
    
    load_regs(regsdump);
    load_memory(memdump);
    stack_load(stackdump,stacksize);
    
    free(stackdump);
}

void save_state(char *filename)
{
    FILE *state = fopen(filename,"w");
    uint16_t regsdump[NUM_REGISTERS+1];
    uint16_t memdump[MEMSIZE];
    uint16_t *stackdump;
    uint32_t stacksize;
    
    dump_regs(regsdump);
    dump_memory(memdump);
    stacksize = stack_dump(&stackdump);
    
    fwrite(regsdump,sizeof(uint16_t),NUM_REGISTERS+1,state);
    fwrite(memdump,sizeof(uint16_t),MEMSIZE,state);
    fwrite(stackdump,sizeof(uint16_t),stacksize,state);
    fclose(state);
    free(stackdump);
}

void query()
{
    //TODO discard stdin
    uint8_t end = 0;
    uint16_t bpoint;
    uint16_t mempos;
    char input[100] = {0};
    char filename[32];
    uint8_t reg;
    uint8_t value;
    while(!end)
    {
        printf("\n> ");
        char command = 0;
        fgets(input,100,stdin);
        command = input[0];
        if (command != '\n')
        {
            lastchoice = command;
        }
        else
        {
            command = lastchoice;
        }
        switch (command)
        {
            case 'b':
                sscanf(input,"b %d\n",&bpoint);
                fprintf(stderr,"Set breakpoint %d to %d",nbpoints,bpoint);
                breakpoints[nbpoints] = bpoint;
                nbpoints = nbpoints + 1 % 0xFF;
                break;
            case 'd':
                sscanf(input,"d %d\n",&bpoint);
                fprintf(stderr,"Deleted breakpoint %d",bpoint);
                breakpoints[bpoint] = 0;
                break;
            case 'c':
                breakpoint = 0;
                end = 1;
                break;
            case 'n':
                end = 1;
                break;
            case 'r':
                print_regs();
                break;
            case 'm':
                sscanf(input,"m %d\n",&mempos);
                fprintf(stderr,"%d: %02x\n",mempos,mem[mempos]);
                break;
            case 's':
                sscanf(input,"s %s\n",filename);
                save_state(filename);
                fprintf(stderr,"Saved state as %s",filename);
                break;
            case 'l':
                sscanf(input,"l %s\n",filename);
                load_state(filename);
                fprintf(stderr,"Loaded state as %s",filename);
                break;
            case 'w':
                //FIXME ALREADY
                sscanf(input,"w %d %d\n",&reg,&value);
                fprintf(stderr,"Setting register %d to %d",reg,value);
                regs[reg] = value;
                break;
            default:
                break;
        }
    }
}

uint8_t in_breakpoint(uint16_t pc)
{
    uint8_t i;
    for(i = 0; i < nbpoints; i++)
    {
        if(breakpoints[i] == pc)
        {
            return 1;
        }
    }
    return 0;
}

uint16_t fetch_debug()
{
    uint16_t value = mem[pc++];
    /*if(breakpoint)
    {
        fprintf(stderr,"0x%2x (0x%2x): %d", pc, pc * sizeof(uint16_t),value);
        fprintf(stderr," cycle: %d\n", cycle_count++);
    }*/
    return value;
}

void translate_args(uint16_t a1, uint16_t a2, uint16_t a3, char *arg1, char *arg2, char *arg3)
{
    if(a1 > MAX_INT)
    {
        sprintf(arg1,"r%d",a1-(MAX_INT+1));
    }
    else
    {
        sprintf(arg1,"%d",a1);
    }
    
    if(a2 > MAX_INT)
    {
        sprintf(arg2,"r%d",a2-(MAX_INT+1));
    }
    else
    {
        sprintf(arg2,"%d",a2);
    }
    
    if(a3 > MAX_INT)
    {
        sprintf(arg3,"r%d",a3-(MAX_INT+1));
    }
    else
    {
        sprintf(arg3,"%d",a3);
    }
    
}

void print_instruction(uint16_t opcode, uint16_t a1, uint16_t a2, uint16_t a3)
{
    char arg1[10];
    char arg2[10];
    char arg3[10];
    translate_args(a1,a2,a3,arg1,arg2,arg3);
    switch(opcode)
    {
        case HALT:
            fprintf(stderr,"HALT\n");
            break;
        case MOV:
            fprintf(stderr,"MOV %s %s\n",arg1,arg2);
            break;
        case PUSH:
            fprintf(stderr,"PUSH %s\n",arg1);
            break;
        case POP:
            fprintf(stderr,"POP %s\n",arg1);
            break;
        case TEQ:
            fprintf(stderr,"TEQ %s %s %s\n",arg1,arg2,arg3);
            break;
        case TGT:
            fprintf(stderr,"TGT %s %s %s\n",arg1,arg2,arg3);
            break;
        case JMP:
            fprintf(stderr,"JMP %s\n",arg1);
            break;
        case JNZ:
            fprintf(stderr,"JNZ %s %s\n",arg1,arg2);
            break;
        case JZ:
            fprintf(stderr,"JZ %s %s\n",arg1,arg2);
            break;
        case ADD:
            fprintf(stderr,"ADD %s %s %s\n",arg1,arg2,arg3);
            break;
        case MUL:
            fprintf(stderr,"MUL %s %s %s\n",arg1,arg2,arg3);
            break;
        case MOD:
            fprintf(stderr,"MOD %s %s %s\n",arg1,arg2,arg3);
            break;
        case AND:
            fprintf(stderr,"AND %s %s %s\n",arg1,arg2,arg3);
            break;
        case OR:
            fprintf(stderr,"OR %s %s %s\n",arg1,arg2,arg3);
            break;
        case NOT:
            fprintf(stderr,"NOT %s %s\n",arg1,arg2);
            break;
        case LOAD:
            fprintf(stderr,"LOAD %s %s\n",arg1,arg2);
            break;
        case STOR:
            fprintf(stderr,"STOR %s %s\n",arg1,arg2);
            break;
        case CALL:
            fprintf(stderr,"CALL %s\n",arg1);
            break;
        case RET:
            fprintf(stderr,"RET\n");
            break;
        case OUT:
            fprintf(stderr,"OUT %s\n",arg1);
            break;
        case IN:
            fprintf(stderr,"IN %s\n",arg1);
            break;
        case NOP:
            fprintf(stderr,"NOP\n");
            break;
        default:
            fprintf(stderr,"UNK %d\n", opcode);
            break;
    }
}


void debug_program()
{
    memset(breakpoints,0x00,0xFF);
    uint16_t arg1;
    uint16_t arg2;
    uint16_t arg3;
    for(;;)
    {
        if(in_breakpoint(pc) || breakpoint)
        {
            breakpoint = 1;
            fprintf(stderr, "%d: ", pc);
            print_instruction(mem[pc], mem[pc+1], mem[pc+2], mem[pc+3]);
            query();
        }
        uint16_t opcode = fetch_debug();
        decode_instruction(opcode, &arg1, &arg2, &arg3);
        if (execute_instruction(opcode, arg1, arg2, arg3))
        {
            return;
        }
    }
}