745 |
#define RW_STATE_LATCHED_WORD1 5 |
#define RW_STATE_LATCHED_WORD1 5 |
746 |
|
|
747 |
typedef struct PITChannelState { |
typedef struct PITChannelState { |
748 |
uint16_t count; |
int count; /* can be 65536 */ |
749 |
uint16_t latched_count; |
uint16_t latched_count; |
750 |
uint8_t rw_state; |
uint8_t rw_state; |
751 |
uint8_t mode; |
uint8_t mode; |
752 |
uint8_t bcd; /* not supported */ |
uint8_t bcd; /* not supported */ |
753 |
uint8_t gate; /* timer start */ |
uint8_t gate; /* timer start */ |
754 |
int64_t count_load_time; |
int64_t count_load_time; |
755 |
|
int64_t count_last_edge_check_time; |
756 |
} PITChannelState; |
} PITChannelState; |
757 |
|
|
758 |
PITChannelState pit_channels[3]; |
PITChannelState pit_channels[3]; |
759 |
int speaker_data_on; |
int speaker_data_on; |
760 |
|
int pit_min_timer_count = 0; |
761 |
|
|
762 |
int64_t ticks_per_sec; |
int64_t ticks_per_sec; |
763 |
|
|
787 |
ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; |
ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; |
788 |
} |
} |
789 |
|
|
790 |
|
/* compute with 96 bit intermediate result: (a*b)/c */ |
791 |
|
static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) |
792 |
|
{ |
793 |
|
union { |
794 |
|
uint64_t ll; |
795 |
|
struct { |
796 |
|
#ifdef WORDS_BIGENDIAN |
797 |
|
uint32_t high, low; |
798 |
|
#else |
799 |
|
uint32_t low, high; |
800 |
|
#endif |
801 |
|
} l; |
802 |
|
} u, res; |
803 |
|
uint64_t rl, rh; |
804 |
|
|
805 |
|
u.ll = a; |
806 |
|
rl = (uint64_t)u.l.low * (uint64_t)b; |
807 |
|
rh = (uint64_t)u.l.high * (uint64_t)b; |
808 |
|
rh += (rl >> 32); |
809 |
|
res.l.high = rh / c; |
810 |
|
res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; |
811 |
|
return res.ll; |
812 |
|
} |
813 |
|
|
814 |
static int pit_get_count(PITChannelState *s) |
static int pit_get_count(PITChannelState *s) |
815 |
{ |
{ |
816 |
int64_t d; |
uint64_t d; |
817 |
int counter; |
int counter; |
818 |
|
|
819 |
d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) / |
d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); |
|
ticks_per_sec; |
|
820 |
switch(s->mode) { |
switch(s->mode) { |
821 |
case 0: |
case 0: |
822 |
case 1: |
case 1: |
834 |
/* get pit output bit */ |
/* get pit output bit */ |
835 |
static int pit_get_out(PITChannelState *s) |
static int pit_get_out(PITChannelState *s) |
836 |
{ |
{ |
837 |
int64_t d; |
uint64_t d; |
838 |
int out; |
int out; |
839 |
|
|
840 |
d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) / |
d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); |
|
ticks_per_sec; |
|
841 |
switch(s->mode) { |
switch(s->mode) { |
842 |
default: |
default: |
843 |
case 0: |
case 0: |
863 |
return out; |
return out; |
864 |
} |
} |
865 |
|
|
866 |
|
/* get the number of 0 to 1 transitions we had since we call this |
867 |
|
function */ |
868 |
|
/* XXX: maybe better to use ticks precision to avoid getting edges |
869 |
|
twice if checks are done at very small intervals */ |
870 |
|
static int pit_get_out_edges(PITChannelState *s) |
871 |
|
{ |
872 |
|
uint64_t d1, d2; |
873 |
|
int64_t ticks; |
874 |
|
int ret, v; |
875 |
|
|
876 |
|
ticks = cpu_get_ticks(); |
877 |
|
d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, |
878 |
|
PIT_FREQ, ticks_per_sec); |
879 |
|
d2 = muldiv64(ticks - s->count_load_time, |
880 |
|
PIT_FREQ, ticks_per_sec); |
881 |
|
s->count_last_edge_check_time = ticks; |
882 |
|
switch(s->mode) { |
883 |
|
default: |
884 |
|
case 0: |
885 |
|
if (d1 < s->count && d2 >= s->count) |
886 |
|
ret = 1; |
887 |
|
else |
888 |
|
ret = 0; |
889 |
|
break; |
890 |
|
case 1: |
891 |
|
ret = 0; |
892 |
|
break; |
893 |
|
case 2: |
894 |
|
d1 /= s->count; |
895 |
|
d2 /= s->count; |
896 |
|
ret = d2 - d1; |
897 |
|
break; |
898 |
|
case 3: |
899 |
|
v = s->count - (s->count >> 1); |
900 |
|
d1 = (d1 + v) / s->count; |
901 |
|
d2 = (d2 + v) / s->count; |
902 |
|
ret = d2 - d1; |
903 |
|
break; |
904 |
|
case 4: |
905 |
|
case 5: |
906 |
|
if (d1 < s->count && d2 >= s->count) |
907 |
|
ret = 1; |
908 |
|
else |
909 |
|
ret = 0; |
910 |
|
break; |
911 |
|
} |
912 |
|
return ret; |
913 |
|
} |
914 |
|
|
915 |
|
static inline void pit_load_count(PITChannelState *s, int val) |
916 |
|
{ |
917 |
|
if (val == 0) |
918 |
|
val = 0x10000; |
919 |
|
s->count_load_time = cpu_get_ticks(); |
920 |
|
s->count_last_edge_check_time = s->count_load_time; |
921 |
|
s->count = val; |
922 |
|
if (s == &pit_channels[0] && val <= pit_min_timer_count) { |
923 |
|
fprintf(stderr, |
924 |
|
"\nWARNING: vl: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", |
925 |
|
PIT_FREQ / pit_min_timer_count); |
926 |
|
} |
927 |
|
} |
928 |
|
|
929 |
void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
930 |
{ |
{ |
931 |
int channel, access; |
int channel, access; |
932 |
PITChannelState *s; |
PITChannelState *s; |
933 |
|
|
934 |
addr &= 3; |
addr &= 3; |
935 |
if (addr == 3) { |
if (addr == 3) { |
936 |
channel = val >> 6; |
channel = val >> 6; |
944 |
s->rw_state = RW_STATE_LATCHED_WORD0; |
s->rw_state = RW_STATE_LATCHED_WORD0; |
945 |
break; |
break; |
946 |
default: |
default: |
947 |
|
s->mode = (val >> 1) & 7; |
948 |
|
s->bcd = val & 1; |
949 |
s->rw_state = access - 1 + RW_STATE_LSB; |
s->rw_state = access - 1 + RW_STATE_LSB; |
950 |
break; |
break; |
951 |
} |
} |
|
s->mode = (val >> 1) & 7; |
|
|
s->bcd = val & 1; |
|
952 |
} else { |
} else { |
953 |
s = &pit_channels[addr]; |
s = &pit_channels[addr]; |
954 |
switch(s->rw_state) { |
switch(s->rw_state) { |
955 |
case RW_STATE_LSB: |
case RW_STATE_LSB: |
956 |
s->count_load_time = cpu_get_ticks(); |
pit_load_count(s, val); |
|
s->count = val; |
|
957 |
break; |
break; |
958 |
case RW_STATE_MSB: |
case RW_STATE_MSB: |
959 |
s->count_load_time = cpu_get_ticks(); |
pit_load_count(s, val << 8); |
|
s->count = (val << 8); |
|
960 |
break; |
break; |
961 |
case RW_STATE_WORD0: |
case RW_STATE_WORD0: |
962 |
case RW_STATE_WORD1: |
case RW_STATE_WORD1: |
963 |
if (s->rw_state & 1) { |
if (s->rw_state & 1) { |
964 |
s->count_load_time = cpu_get_ticks(); |
pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); |
|
s->count = (s->latched_count & 0xff) | (val << 8); |
|
965 |
} else { |
} else { |
966 |
s->latched_count = val; |
s->latched_count = val; |
967 |
} |
} |
1019 |
|
|
1020 |
void pit_init(void) |
void pit_init(void) |
1021 |
{ |
{ |
1022 |
pit_channels[0].gate = 1; |
PITChannelState *s; |
1023 |
pit_channels[1].gate = 1; |
int i; |
1024 |
pit_channels[2].gate = 0; |
|
1025 |
|
cpu_calibrate_ticks(); |
1026 |
|
|
1027 |
|
for(i = 0;i < 3; i++) { |
1028 |
|
s = &pit_channels[i]; |
1029 |
|
s->mode = 3; |
1030 |
|
s->gate = (i != 2); |
1031 |
|
pit_load_count(s, 0); |
1032 |
|
} |
1033 |
|
|
1034 |
register_ioport_writeb(0x40, 4, pit_ioport_write); |
register_ioport_writeb(0x40, 4, pit_ioport_write); |
1035 |
register_ioport_readb(0x40, 3, pit_ioport_read); |
register_ioport_readb(0x40, 3, pit_ioport_read); |
1036 |
|
|
1037 |
register_ioport_readb(0x61, 1, speaker_ioport_read); |
register_ioport_readb(0x61, 1, speaker_ioport_read); |
1038 |
register_ioport_writeb(0x61, 1, speaker_ioport_write); |
register_ioport_writeb(0x61, 1, speaker_ioport_write); |
|
cpu_calibrate_ticks(); |
|
1039 |
} |
} |
1040 |
|
|
1041 |
/***********************************************************/ |
/***********************************************************/ |
1553 |
s->rcnt == 0) { |
s->rcnt == 0) { |
1554 |
s->isr |= ENISR_RDC; |
s->isr |= ENISR_RDC; |
1555 |
ne2000_update_irq(s); |
ne2000_update_irq(s); |
1556 |
|
/* XXX: find a better solution for irqs */ |
1557 |
|
cpu_x86_interrupt(global_env); |
1558 |
} |
} |
1559 |
if (val & E8390_TRANS) { |
if (val & E8390_TRANS) { |
1560 |
net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); |
net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); |
1764 |
} |
} |
1765 |
|
|
1766 |
static int timer_irq_pending; |
static int timer_irq_pending; |
1767 |
|
static int timer_irq_count; |
1768 |
|
|
1769 |
static void host_alarm_handler(int host_signum, siginfo_t *info, |
static void host_alarm_handler(int host_signum, siginfo_t *info, |
1770 |
void *puc) |
void *puc) |
1771 |
{ |
{ |
1772 |
/* just exit from the cpu to have a chance to handle timers */ |
/* NOTE: since usually the OS asks a 100 Hz clock, there can be |
1773 |
cpu_x86_interrupt(global_env); |
some drift between cpu_get_ticks() and the interrupt time. So |
1774 |
timer_irq_pending = 1; |
we queue some interrupts to avoid missing some */ |
1775 |
|
timer_irq_count += pit_get_out_edges(&pit_channels[0]); |
1776 |
|
if (timer_irq_count) { |
1777 |
|
if (timer_irq_count > 2) |
1778 |
|
timer_irq_count = 2; |
1779 |
|
timer_irq_count--; |
1780 |
|
/* just exit from the cpu to have a chance to handle timers */ |
1781 |
|
cpu_x86_interrupt(global_env); |
1782 |
|
timer_irq_pending = 1; |
1783 |
|
} |
1784 |
} |
} |
1785 |
|
|
1786 |
void help(void) |
void help(void) |
1808 |
struct sigaction act; |
struct sigaction act; |
1809 |
struct itimerval itv; |
struct itimerval itv; |
1810 |
CPUX86State *env; |
CPUX86State *env; |
1811 |
|
const char *tmpdir; |
1812 |
|
|
1813 |
/* we never want that malloc() uses mmap() */ |
/* we never want that malloc() uses mmap() */ |
1814 |
mallopt(M_MMAP_THRESHOLD, 4096 * 1024); |
mallopt(M_MMAP_THRESHOLD, 4096 * 1024); |
1815 |
|
|
1853 |
net_init(); |
net_init(); |
1854 |
|
|
1855 |
/* init the memory */ |
/* init the memory */ |
1856 |
strcpy(phys_ram_file, "/tmp/vlXXXXXX"); |
tmpdir = getenv("VLTMPDIR"); |
1857 |
|
if (!tmpdir) |
1858 |
|
tmpdir = "/tmp"; |
1859 |
|
snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); |
1860 |
if (mkstemp(phys_ram_file) < 0) { |
if (mkstemp(phys_ram_file) < 0) { |
1861 |
fprintf(stderr, "Could not create temporary memory file\n"); |
fprintf(stderr, "Could not create temporary memory file '%s'\n", |
1862 |
|
phys_ram_file); |
1863 |
exit(1); |
exit(1); |
1864 |
} |
} |
1865 |
phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); |
phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); |
1866 |
if (phys_ram_fd < 0) { |
if (phys_ram_fd < 0) { |
1867 |
fprintf(stderr, "Could not open temporary memory file\n"); |
fprintf(stderr, "Could not open temporary memory file '%s'\n", |
1868 |
|
phys_ram_file); |
1869 |
exit(1); |
exit(1); |
1870 |
} |
} |
1871 |
ftruncate(phys_ram_fd, phys_ram_size); |
ftruncate(phys_ram_fd, phys_ram_size); |
1965 |
env->eflags = 0x2; |
env->eflags = 0x2; |
1966 |
|
|
1967 |
itv.it_interval.tv_sec = 0; |
itv.it_interval.tv_sec = 0; |
1968 |
itv.it_interval.tv_usec = 10 * 1000; |
itv.it_interval.tv_usec = 1000; |
1969 |
itv.it_value.tv_sec = 0; |
itv.it_value.tv_sec = 0; |
1970 |
itv.it_value.tv_usec = 10 * 1000; |
itv.it_value.tv_usec = 10 * 1000; |
1971 |
setitimer(ITIMER_REAL, &itv, NULL); |
setitimer(ITIMER_REAL, &itv, NULL); |
1972 |
|
/* we probe the tick duration of the kernel to inform the user if |
1973 |
|
the emulated kernel requested a too high timer frequency */ |
1974 |
|
getitimer(ITIMER_REAL, &itv); |
1975 |
|
pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / |
1976 |
|
1000000; |
1977 |
|
|
1978 |
for(;;) { |
for(;;) { |
1979 |
struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd; |
struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd; |