예제 #1
0
/*
  one-pole highpass filter
   y[n] = alpha * (y[n-1] + x[n] - x[n-1])

   fcut_hz corresponds to 3 dB point
*/
void dc_filter_init(dc_filter_t *pstate, float fcut_hz, float sample_rate_hz)
{
    float temp;

    memset(pstate, 0, sizeof(dc_filter_t));
    //
    // alpha = 32767 - fcut * 26 * 8 / samplerate_khz
    //
    // warning:  if alpha is too large, then lack of precision in 
    // q15 * i16 multiply will
    // result in sticky bits
    //
    temp = 26.0f * 8.0f / (sample_rate_hz/1000.0f);
    temp = fcut_hz * temp;

    pstate->alpha_16 = (int16_t)32767 - (int16_t)temp;
    utils_log("/ndc_filter: alpha_i16 = %d\n",pstate->alpha_16);
    if (pstate->alpha_16 <= 0)
    {
        utils_log("fcut_hz = ");
        utils_print_float(fcut_hz,5);
        utils_log("\n");
        utils_log("alpha must be > 0");
        UTILS_ASSERT(0);
    }
}
예제 #2
0
char gameboy_restore_stat(int idx)
{
    char path[256];
    char buf[6];

    /* ensure i'm in pause */
    gameboy_set_pause(1);

    /* build output file name */
    snprintf(path, sizeof(path), "%s/%s.%d.stat", global_save_folder,
             global_rom_name, idx);

    FILE *fp = fopen(path, "r+");

    if (fp == NULL)
    {
        utils_log("Cannot open stat file\n");
        return 1;
    }

    /* read version */
    fread(buf, 1, 6, fp);

    if (memcmp(buf, "000001", 6))
    {
        utils_log("Version of stat file doesnt match\n");
        return 1;
    }

    /* restore CPU status */
    fread(&state, 1, sizeof(z80_state_t), fp);

    state.f = (uint8_t *) &state.flags;
    state.bc = (uint16_t *) &state.c;
    state.de = (uint16_t *) &state.e;
    state.hl = (uint16_t *) &state.l;

    /* dump every module */
    cycles_restore_stat(fp);
    sound_restore_stat(fp);
    gpu_restore_stat(fp);
    serial_restore_stat(fp);
    mmu_restore_stat(fp);

    fclose(fp);

    return 0;
}
예제 #3
0
char cartridge_load(char *file_gb) 
{
    FILE *fp;
    int i,z = 0;

    /* open ROM file */
    if ((fp = fopen(file_gb, "r")) == NULL) 
        return 1;

    /* read all the content into rom buffer */
    size_t sz = fread(rom, 1, (2 << 24), fp);

    /* check for errors   */
    if (sz < 1) 
        return 1;

    /* close */
    fclose(fp);
 
    /* gameboy color? */
    if (rom[0x143] == 0xC0 || rom[0x143] == 0x80)
    {
        utils_log("Gameboy Color cartridge\n");
        global_cgb = 1;
    }
    else
    {
        utils_log("Gameboy Classic cartridge\n");
        global_cgb = 0;
    }

    /* get cartridge infos */
    uint8_t mbc = rom[0x147];

    utils_log("Cartridge code: %02x\n", mbc);

    switch (mbc)
    {
        case 0x00: utils_log("ROM ONLY\n"); break;
        case 0x01: utils_log("MBC1\n"); break;
        case 0x02: utils_log("MBC1 + RAM\n"); break;
        case 0x03: utils_log("MBC1 + RAM + BATTERY\n"); break;
        case 0x05: utils_log("MBC2\n"); break;
        case 0x06: mmu_init_ram(512); utils_log("MBC2 + BATTERY\n"); break;
        case 0x10: utils_log("MBC3 + TIMER + RAM + BATTERY\n"); break;
        case 0x11: utils_log("MBC3\n"); break;
        case 0x12: utils_log("MBC3 + RAM\n"); break;
        case 0x13: utils_log("MBC3 + RAM + BATTERY\n"); break;
        case 0x19: utils_log("MBC5\n"); break;
        case 0x1A: utils_log("MBC5 + RAM\n"); break;
        case 0x1B: utils_log("MBC5 + RAM + BATTERY\n"); break;
        case 0x1C: utils_log("MBC5 + RUMBLE\n"); break;
        case 0x1D: utils_log("MBC5 + RUMBLE + RAM\n"); break;
        case 0x1E: utils_log("MBC5 + RUMBLE + RAM + BATTERY\n"); break;

        default: utils_log("Unknown cartridge type: %02x\n", mbc);
                 return 2;
    }

    /* title */
    for (i=0x134; i<0x143; i++)
        if (rom[i] > 0x40 && rom[i] < 0x5B)
            global_cart_name[z++] = rom[i];

    global_cart_name[z] = '\0';

    utils_log("%s\n", global_cart_name);

    /* get ROM banks */
    uint8_t byte = rom[0x148];

    utils_log("ROM: ");

    switch (byte)
    {
        case 0x00: utils_log("0 banks\n"); break;
        case 0x01: utils_log("4 banks\n"); break;
        case 0x02: utils_log("8 banks\n"); break;
        case 0x03: utils_log("16 banks\n"); break;
        case 0x04: utils_log("32 banks\n"); break;
        case 0x05: utils_log("64 banks\n"); break;
        case 0x06: utils_log("128 banks\n"); break;
        case 0x07: utils_log("256 banks\n"); break;
        case 0x52: utils_log("72 banks\n"); break;
        case 0x53: utils_log("80 banks\n"); break;
        case 0x54: utils_log("96 banks\n"); break;
    }

    /* init MMU */
    mmu_init(mbc, byte);

    /* get RAM banks */
    byte = rom[0x149];

    utils_log("RAM: ");

    switch (byte)
    {
        case 0x00: utils_log("NO RAM\n"); break;
        case 0x01: mmu_init_ram(1 << 11); utils_log("2 kB\n"); break;
        case 0x02: 
                   /* MBC5 got bigger values */
                   if (mbc >= 0x19 && mbc <= 0x1E)
                   {
                       mmu_init_ram(1 << 16); 
                       utils_log("64 kB\n"); 
                   }
                   else
                   {
                       mmu_init_ram(1 << 13); 
                       utils_log("8 kB\n"); 
                   }
                   break;
        case 0x03: mmu_init_ram(1 << 15); utils_log("32 kB\n"); break;
        case 0x04: mmu_init_ram(1 << 17); utils_log("128 kB\n"); break;
        case 0x05: mmu_init_ram(1 << 16); utils_log("64 kB\n"); break;
    }

    /* save base name of the rom */
    strncpy(global_rom_name, basename(file_gb), 256);

    /* build file.sav */
    snprintf(file_sav, sizeof(file_sav), "%s/%s.sav", 
                                         global_save_folder, global_rom_name);

    /* build file.rtc */
    snprintf(file_rtc, sizeof(file_rtc), "%s/%s.rtc", 
                                         global_save_folder, global_rom_name);

    /* restore saved RAM if it's the case */
    mmu_restore_ram(file_sav);

    /* restore saved RTC if it's the case */
    mmu_restore_rtc(file_rtc);

    /* load FULL ROM at 0x0000 address of system memory */
    mmu_load_cartridge(rom, sz);

    return 0; 
}
예제 #4
0
void *network_start_thread(void *args)
{
    utils_log("Starting network thread\n");

    /* open socket sending broadcast messages */
    network_sock_broad = socket(AF_INET, SOCK_DGRAM, 0);
    
    /* exit on error */
    if (network_sock_broad < 1)
    {
        utils_log("Error opening broadcast socket");
        return NULL;
    }
        
    /* open socket sending/receiving serial cable data */
    network_sock_bound = socket(AF_INET, SOCK_DGRAM, 0);

    /* exit on error */
    if (network_sock_bound < 1)
    {
        utils_log("Error opening serial-link socket");
        close (network_sock_broad);
        return NULL;
    }
    
    /* enable to broadcast */
    int enable=1;
    setsockopt(network_sock_broad, SOL_SOCKET, SO_BROADCAST, 
               &enable, sizeof(enable));

    /* prepare dest stuff */
    struct sockaddr_in broadcast_addr;    
    struct sockaddr_in bound_addr;    
    struct sockaddr_in addr_from;    
    socklen_t addr_from_len = sizeof(addr_from);

    memset(&broadcast_addr, 0, sizeof(broadcast_addr));  
    broadcast_addr.sin_family = AF_INET;                
    broadcast_addr.sin_addr.s_addr = INADDR_BROADCAST;
//    inet_aton("239.255.0.37",
//              (struct in_addr *) &broadcast_addr.sin_addr.s_addr);
    //inet_aton("192.168.10.168", 
    //          (struct in_addr *) &broadcast_addr.sin_addr.s_addr);
    broadcast_addr.sin_port = htons(64333);             

    /* setup listening socket */
    memset(&bound_addr, 0, sizeof(bound_addr));   
    bound_addr.sin_family = AF_INET;                 
    bound_addr.sin_addr.s_addr = INADDR_ANY;   
    bound_addr.sin_port = htons(64333);                
   
    /* bind to selected port */
    if (bind(network_sock_bound, (struct sockaddr *) &bound_addr, 
             sizeof(bound_addr)))
    {
        utils_log("Error binding to port 64333");

        /* close sockets and exit */
        close(network_sock_broad);
        close(network_sock_bound);
        
        return NULL;
    }

    /* assign it to our multicast group */
/*    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr=inet_addr("239.255.0.37");
    mreq.imr_interface.s_addr=htonl(INADDR_ANY);

    if (setsockopt(network_sock_bound, IPPROTO_IP, IP_ADD_MEMBERSHIP,
               &mreq, sizeof(mreq)) < 0)
    {
        utils_log("Error joining multicast network");

        close(network_sock_broad);
        close(network_sock_bound);
        
        return NULL;
    }*/

    fd_set rfds;
    char buf[64];
    int ret;
    ssize_t recv_ret;
    struct timeval tv;
    int timeouts = 4;
    unsigned int v, clock, prog;
    // uint16_t prog;

    /* message parts */
    char         msg_type;
    unsigned int msg_uuid;
    char         msg_content[64];

    /* generate a random uuid */
    srand(time(NULL));
    network_uuid = rand() & 0xFFFFFFFF;

    /* set callback in case of data to send */
    serial_set_send_cb(&network_send_data);

    /* declare network is running */
    network_running = 1;

    utils_log("Network thread started\n");

    /* loop forever */
    while (network_running)
    {
        FD_ZERO(&rfds);
        FD_SET(network_sock_bound, &rfds);

        /* wait one second */
        tv.tv_sec = 1;
        tv.tv_usec = 0;

        /* one second timeout OR something received */
        ret = select(network_sock_bound + 1, &rfds, NULL, NULL, &tv);

        // utils_log_urgent("SELECT RET: %d\n", ret);

        /* error! */
        if (ret == -1)
            break;

        /* ret 0 = timeout */
        if (ret == 0)
        {
            if (++timeouts == 5)
            {
                /* build output message */
                sprintf(buf, "B%08x%s", network_uuid, global_cart_name);

                /* send broadcast message */
                sendto(network_sock_broad, buf, strlen(buf), 0, 
                             (struct sockaddr *) &broadcast_addr, 
                             sizeof(broadcast_addr));  

                timeouts = 0;
            }
        }
        else
        {
            /* reset message content */
            bzero(buf, sizeof(buf));
            bzero(msg_content, sizeof(msg_content));

            /* exit if an error occour */
            if ((recv_ret = recvfrom(network_sock_bound, buf, 64, 0,
                         (struct sockaddr *) &addr_from, 
                         (socklen_t *) &addr_from_len)) < 1)
                break;

            /* dissect message */
            if (sscanf(buf, "%c%08x%s", 
                       &msg_type, &msg_uuid, msg_content) == 3)
            {
                /* was it send by myself? */
                if (msg_uuid != network_uuid)
                {
                    /* is it a serial message? */
                    if (msg_type == 'M')
                    {
                        /* extract value from hex string */
                        sscanf(msg_content, "%02x%02x%02x", &v, &clock, &prog);

                        /* tell serial module something has arrived */
                        serial_recv_byte((uint8_t) v, (uint8_t) clock);

                        /*if (clock == 0)
                        {
                            utils_ts_log("SEM POST\n");

                            network_sem_post(&network_sem);
                        } */
                    }
                    else if (msg_type == 'B')
                    {
                        /* someone is claiming is playing with the same game? */
                        if (strcmp(msg_content, global_cart_name) == 0 && 
                            serial.peer_connected == 0)
                        {
                            /* save sender */
                            memcpy(&network_peer_addr, &addr_from, 
                                   sizeof(struct sockaddr_in));

                            /* just change dst port */
                            network_peer_addr.sin_port = htons(64333);

                            /* notify the other peer by sending a b message */
                            sprintf(buf, "B%08x%s", network_uuid, 
                                    global_cart_name);

                            /* send broadcast message */
                            sendto(network_sock_broad, buf, strlen(buf), 0,
                                   (struct sockaddr *) &network_peer_addr,
                                   sizeof(network_peer_addr));

                            /* log that peer is connected */
                            utils_log("Peer connected: %s\n", 
			        inet_ntoa(network_peer_addr.sin_addr));

                            /* YEAH */
                            serial.peer_connected = 1;
                        }
                    } 
                }
            }
        }
    }
   
    /* free serial */
    serial.peer_connected = 0;

    /* close sockets */
    close(network_sock_broad);
    close(network_sock_bound);    
    
    return NULL;
}
예제 #5
0
void gameboy_run()
{
    uint8_t op;

    /* reset counter */
    cycles.cnt = 0;

    /* get interrupt flags and interrupt enables */
    uint8_t *int_e;
    uint8_t *int_f;

    /* pointers to memory location of interrupt enables/flags */
    int_e = mmu_addr(0xFFFF);
    int_f = mmu_addr(0xFF0F);

    /* start at normal speed */
    global_cpu_double_speed = 0;

    /* run stuff!                                                          */
    /* mechanism is simple.                                                */
    /* 1) execute instruction 2) update cycles counter 3) check interrupts */
    /* and repeat forever                                                  */
    while (!global_quit)
    {
        /*if (global_slow_down)
        {
            usleep(100000);
            global_slow_down = 0;
        }*/

        /* pause? */
        while (global_pause)
            sem_wait(&gameboy_sem);

        /* get op */
        op = mmu_read(state.pc);

        /* print out CPU state if enabled by debug flag */
        if (global_debug)
        {
            utils_log("OP: %02x F: %02x PC: %04x:%02x:%02x SP: %04x:%02x:%02x ",
                      op, *state.f & 0xd0, state.pc,
                      mmu_read_no_cyc(state.pc + 1),
                      mmu_read_no_cyc(state.pc + 2), state.sp,
                      mmu_read_no_cyc(state.sp),
                      mmu_read_no_cyc(state.sp + 1));


            utils_log("A: %02x BC: %04x DE: %04x HL: %04x FF41: %02x "
                      "FF44: %02x ENAB: %02x INTE: %02x INTF: %02x\n",
                      state.a, *state.bc,
                      *state.de, *state.hl,
                      mmu_read_no_cyc(0xFF41),
                      mmu_read_no_cyc(0xFF44),
                      state.int_enable,
                      *int_e, *int_f);
        }

        /* execute instruction by the GB Z80 version */
        z80_execute(op);

        /* if last op was Interrupt Enable (0xFB)  */
        /* we need to check for INTR on next cycle */
        if (op == 0xFB)
            continue;

        /* interrupts filtered by enable flags */
        uint8_t int_r = (*int_f & *int_e);

        /* check for interrupts */
        if ((state.int_enable || op == 0x76) && (int_r != 0))
        {
            /* discard useless bits */
            if ((int_r & 0x1F) == 0x00)
                continue;

            /* beware of instruction that doesn't move PC! */
            /* like HALT (0x76)                            */
            if (op == 0x76)
            {
                state.pc++;

                if (state.int_enable == 0)
                    continue;
            }

            /* reset int-enable flag, it will be restored after a RETI op */
            state.int_enable = 0;

            if ((int_r & 0x01) == 0x01)
            {
                /* vblank interrupt triggers RST 5 */

                /* reset flag */
                *int_f &= 0xFE;

                /* handle the interrupt */
                z80_intr(0x0040);
            }
            else if ((int_r & 0x02) == 0x02)
            {
                /* LCD Stat interrupt */

                /* reset flag */
                *int_f &= 0xFD;

                /* handle the interrupt! */
                z80_intr(0x0048);
            }
            else if ((int_r & 0x04) == 0x04)
            {
                /* timer interrupt */

                /* reset flag */
                *int_f &= 0xFB;

                /* handle the interrupt! */
                z80_intr(0x0050);
            }
            else if ((int_r & 0x08) == 0x08)
            {
                /* serial interrupt */

                /* reset flag */
                *int_f &= 0xF7;

                /* handle the interrupt! */
                z80_intr(0x0058);
            }
        }
    }

    /* terminate all the stuff */
    cartridge_term();
    sound_term();
    mmu_term();

    return;
}