// Copyright (C) 2001 MandrakeSoft S.A. // // MandrakeSoft S.A. // 43, rue d'Aboukir // 75002 Paris - France // http://www.linux-mandrake.com/ // http://www.mandrakesoft.com/ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "bochs.h" #ifdef WIN32 #ifndef __MINGW32__ // #include // +++ #include #endif #endif #if BX_SHOW_IPS unsigned long ips_count=0; #endif #if defined(PROVIDE_M_IPS) double m_ips; // Millions of Instructions Per Second #endif const Bit64u bx_pc_system_c::COUNTER_INTERVAL = 100000; // constructor bx_pc_system_c::bx_pc_system_c(void) { num_timers = 0; // set ticks period and remaining to max Bit32u value num_cpu_ticks_in_period = num_cpu_ticks_left = (Bit32u) -1; m_ips = 0.0L; for (unsigned int i=0; i < 8; i++) { DRQ[i] = 0; DACK[i] = 0; } TC = 0; HRQ = 0; HLDA = 0; enable_a20 = 1; #if BX_CPU_LEVEL < 2 a20_mask = 0xfffff; #elif BX_CPU_LEVEL == 2 a20_mask = 0xffffff; #else /* 386+ */ a20_mask = 0xffffffff; #endif counter = 0; counter_timer_index = register_timer_ticks(this, bx_pc_system_c::counter_timer_handler, COUNTER_INTERVAL, 1, 1); } void bx_pc_system_c::init_ips(Bit32u ips) { // parameter 'ips' is the processor speed in Instructions-Per-Second m_ips = double(ips) / 1000000.0L; bx_printf("ips = %u\n", (unsigned) ips); } void bx_pc_system_c::raise_HLDA(void) { HLDA = 1; bx_devices.raise_hlda(); HLDA = 0; } void bx_pc_system_c::set_DRQ(unsigned channel, Boolean val) { if (channel > 7) bx_panic("set_DRQ() channel > 7\n"); DRQ[channel] = val; bx_devices.drq(channel, val); } void bx_pc_system_c::set_HRQ(Boolean val) { HRQ = val; if (val) BX_CPU.async_event = 1; else HLDA = 0; // ??? needed? } void bx_pc_system_c::set_TC(Boolean val) { TC = val; } void bx_pc_system_c::set_DACK(unsigned channel, Boolean val) { DACK[channel] = val; } void bx_pc_system_c::dma_write8(Bit32u phy_addr, unsigned channel) { // DMA controlled xfer of byte from I/O to Memory Bit8u data_byte; UNUSED(channel); bx_devices.dma_write8(channel, &data_byte); BX_MEM.write_physical(phy_addr, 1, &data_byte); BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, data_byte); } void bx_pc_system_c::dma_read8(Bit32u phy_addr, unsigned channel) { // DMA controlled xfer of byte from Memory to I/O Bit8u data_byte; UNUSED(channel); BX_MEM.read_physical(phy_addr, 1, &data_byte); bx_devices.dma_read8(channel, &data_byte); BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, data_byte); } #if (BX_NUM_SIMULATORS < 2) void bx_pc_system_c::set_INTR(Boolean value) { INTR = value; BX_CPU.set_INTR(value); } #endif // // Read from the IO memory address space // Bit32u bx_pc_system_c::inp(Bit16u addr, unsigned io_len) { Bit32u ret; ret = bx_devices.inp(addr, io_len); return( ret ); } // // Write to the IO memory address space. // void bx_pc_system_c::outp(Bit16u addr, Bit32u value, unsigned io_len) { bx_devices.outp(addr, value, io_len); } void bx_pc_system_c::set_enable_a20(Bit8u value) { #if BX_CPU_LEVEL < 2 bx_panic("set_enable_a20() called: 8086 emulation\n"); #else #if BX_SUPPORT_A20 if (value) { enable_a20 = 1; #if BX_CPU_LEVEL == 2 a20_mask = 0xffffff; /* 286: enable all 24 address lines */ #else /* 386+ */ a20_mask = 0xffffffff; /* 386: enable all 32 address lines */ #endif } else { enable_a20 = 0; a20_mask = 0xffefffff; /* mask off A20 address line */ } BX_DBG_A20_REPORT(value); if (bx_dbg.a20) bx_printf("A20: set() = %u\n", (unsigned) enable_a20); #else bx_printf("set_enable_a20: ignoring: SUPPORT_A20 = 0\n"); #endif // #if BX_SUPPORT_A20 #endif } Boolean bx_pc_system_c::get_enable_a20(void) { #if BX_SUPPORT_A20 if (bx_dbg.a20) bx_printf("A20: get() = %u\n", (unsigned) enable_a20); if (enable_a20) return(1); else return(0); #else bx_printf("get_enable_a20: ignoring: SUPPORT_A20 = 0\n"); return(1); #endif // #if BX_SUPPORT_A20 } int bx_pc_system_c::ResetSignal( PCS_OP operation ) { UNUSED( operation ); // Reset the processor. fprintf(stderr, "# bx_pc_system_c::ResetSignal() called\n"); bx_panic("pc_system.resetsignal() called\n"); return(0); } Bit8u bx_pc_system_c::IAC(void) { return( bx_devices.pic->IAC() ); } void bx_pc_system_c::exit(void) { if (bx_devices.hard_drive) bx_devices.hard_drive->close_harddrive(); bx_printf("Last time is %d\n", BX_CMOS_THIS s.timeval); bx_gui.exit(); } // // bochs timer support // void bx_pc_system_c::timer_handler(void) { Bit64u min; unsigned i; Bit64u delta; // fprintf(stderr, "Time handler ptime = %d\n", bx_pc_system.time_ticks()); delta = num_cpu_ticks_in_period - num_cpu_ticks_left; #if BX_TIMER_DEBUG if (num_cpu_ticks_left != 0) bx_panic("timer_handler: ticks_left!=0\n"); #endif for (i=0; i < num_timers; i++) { timer[i].triggered = 0; if (timer[i].active) { #if BX_TIMER_DEBUG if (timer[i].remaining < delta) { bx_panic("timer_handler: remain < delta\n"); } #endif timer[i].remaining -= delta; if (timer[i].remaining == 0) { timer[i].triggered = 1; // reset remaining period for triggered timer timer[i].remaining = timer[i].period; // if triggered timer is one-shot, deactive if (timer[i].continuous==0) timer[i].active = 0; } } } min = (Bit64u) -1; // max number in Bit64u range for (i=0; i < num_timers; i++) { if (timer[i].active && (timer[i].remaining < min)) min = timer[i].remaining; } num_cpu_ticks_in_period = num_cpu_ticks_left = min; for (i=0; i < num_timers; i++) { // call requested timer function. It may request a different // timer period or deactivate, all cases handled below if (timer[i].triggered) { timer[i].funct(timer[i].this_ptr); } } } void bx_pc_system_c::expire_ticks(void) { unsigned i; Bit64u ticks_delta; ticks_delta = num_cpu_ticks_in_period - num_cpu_ticks_left; if (ticks_delta == 0) return; // no ticks occurred since for (i=0; i= 1 here } } // set new period to number of ticks left num_cpu_ticks_in_period = num_cpu_ticks_left; } int bx_pc_system_c::register_timer( void *this_ptr, void (*funct)(void *), Bit32u useconds, Boolean continuous, Boolean active) { Bit64u instructions; if (num_timers >= BX_MAX_TIMERS) { bx_panic("register_timer: too many registered timers."); } if (this_ptr == NULL) bx_panic("register_timer: this_ptr is NULL\n"); if (funct == NULL) bx_panic("register_timer: funct is NULL\n"); // account for ticks up to now expire_ticks(); // convert useconds to number of instructions instructions = (Bit64u) (double(useconds) * m_ips); return register_timer_ticks(this_ptr, funct, instructions, continuous, active); } int bx_pc_system_c::register_timer_ticks(void* this_ptr, bx_timer_handler_t funct, Bit64u instructions, Boolean continuous, Boolean active) { unsigned i; if (num_timers >= BX_MAX_TIMERS) { bx_panic("register_timer: too many registered timers."); } if (this_ptr == NULL) bx_panic("register_timer: this_ptr is NULL\n"); if (funct == NULL) bx_panic("register_timer: funct is NULL\n"); i = num_timers; num_timers++; timer[i].period = instructions; timer[i].remaining = instructions; timer[i].active = active; timer[i].funct = funct; timer[i].continuous = continuous; timer[i].this_ptr = this_ptr; if (active) { if (num_cpu_ticks_in_period == 0) { // no active timers num_cpu_ticks_in_period = instructions; num_cpu_ticks_left = instructions; } else { if (instructions < num_cpu_ticks_left) { num_cpu_ticks_in_period = instructions; num_cpu_ticks_left = instructions; } } } // return timer id return(i); } void bx_pc_system_c::counter_timer_handler(void* this_ptr) { UNUSED(this_ptr); bx_pc_system.counter++; } #if BX_DEBUGGER void bx_pc_system_c::timebp_handler(void* this_ptr) { BX_CPU_THIS_PTR break_point = BREAK_POINT_TIME; fprintf(stderr, "Time breakpoint triggered\n"); if (timebp_queue_size > 1) { long long new_diff = timebp_queue[1] - bx_pc_system.time_ticks(); bx_pc_system.activate_timer_ticks(timebp_timer, new_diff, 1); } timebp_queue_size--; for (int i = 0; i < timebp_queue_size; i++) timebp_queue[i] = timebp_queue[i+1]; } #endif // BX_DEBUGGER // (mch) Wait for an event. This routine is broken, but the idea is nice... void bx_pc_system_c::wait_for_event() { Bit64u ticks_left = bx_pc_system.num_cpu_ticks_left; // sec = instr / instr_per_sec #ifdef PROVIDE_M_IPS int usecs = (int)(double((Bit64s)ticks_left) / double(m_ips)); #else int usecs = (int)(double((Bit64s)ticks_left) / double(bx_pc_system.m_ips)); #endif struct timeval tv; tv.tv_sec = 0; tv.tv_usec = usecs; select(0, NULL, NULL, NULL, &tv); bx_pc_system.num_cpu_ticks_left = 1; BX_TICK1(); } Bit64u bx_pc_system_c::time_ticks() { return (counter + 1) * COUNTER_INTERVAL - ticks_remaining(counter_timer_index) + ((Bit64u)num_cpu_ticks_in_period - (Bit64u)num_cpu_ticks_left); } void bx_pc_system_c::start_timers(void) { } void bx_pc_system_c::activate_timer_ticks (unsigned timer_index, Bit64u instructions, Boolean continuous) { if (timer_index >= num_timers) bx_panic("activate_timer(): bad timer index given\n"); // set timer continuity to new value (1=continuous, 0=one-shot) timer[timer_index].continuous = continuous; timer[timer_index].active = 1; timer[timer_index].remaining = instructions; if (num_cpu_ticks_in_period == 0) { // no active timers num_cpu_ticks_in_period = instructions; num_cpu_ticks_left = instructions; } else { if (instructions < num_cpu_ticks_left) { num_cpu_ticks_in_period = instructions; num_cpu_ticks_left = instructions; } } } void bx_pc_system_c::activate_timer( unsigned timer_index, Bit32u useconds, Boolean continuous ) { Bit64u instructions; if (timer_index >= num_timers) bx_panic("activate_timer(): bad timer index given\n"); // account for ticks up to now expire_ticks(); // set timer continuity to new value (1=continuous, 0=one-shot) timer[timer_index].continuous = continuous; // if useconds = 0, use default stored in period field // else set new period from useconds if (useconds==0) instructions = timer[timer_index].period; else { // convert useconds to number of instructions instructions = (Bit64u) (double(useconds) * m_ips); timer[timer_index].period = instructions; } timer[timer_index].active = 1; timer[timer_index].remaining = instructions; if (num_cpu_ticks_in_period == 0) { // no active timers num_cpu_ticks_in_period = instructions; num_cpu_ticks_left = instructions; } else { if (instructions < num_cpu_ticks_left) { num_cpu_ticks_in_period = instructions; num_cpu_ticks_left = instructions; } } } void bx_pc_system_c::deactivate_timer( unsigned timer_index ) { if (timer_index >= num_timers) bx_panic("deactivate_timer(): bad timer index given\n"); timer[timer_index].active = 0; }