PowerPC system emulation fixes (Jocelyn Mayer)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2004-04-12 20:39:29 +00:00
parent df475d18d8
commit a541f297a3
24 changed files with 1525 additions and 865 deletions

379
hw/fdc.c
View file

@ -83,7 +83,6 @@ typedef struct fdrive_t {
uint8_t dir; /* Direction */
uint8_t rw; /* Read/write */
/* Media */
fdisk_type_t disk; /* Disk type */
fdisk_flags_t flags;
uint8_t last_sect; /* Nb sector per track */
uint8_t max_track; /* Nb of tracks */
@ -102,7 +101,6 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs)
drv->drflags = 0;
drv->perpendicular = 0;
/* Disk */
drv->disk = FDRIVE_DISK_NONE;
drv->last_sect = 0;
drv->max_track = 0;
}
@ -171,26 +169,113 @@ static void fd_recalibrate (fdrive_t *drv)
drv->rw = 0;
}
/* Recognize floppy formats */
typedef struct fd_format_t {
fdrive_type_t drive;
fdisk_type_t disk;
uint8_t last_sect;
uint8_t max_track;
uint8_t max_head;
const unsigned char *str;
} fd_format_t;
static fd_format_t fd_formats[] = {
/* First entry is default format */
/* 1.44 MB 3"1/2 floppy disks */
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
/* 2.88 MB 3"1/2 floppy disks */
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", },
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
/* 720 kB 3"1/2 floppy disks */
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
/* 1.2 MB 5"1/4 floppy disks */
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", },
/* 720 kB 5"1/4 floppy disks */
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", },
/* 360 kB 5"1/4 floppy disks */
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", },
/* 320 kB 5"1/4 floppy disks */
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", },
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", },
/* 360 kB must match 5"1/4 better than 3"1/2... */
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", },
/* end */
{ FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
};
/* Revalidate a disk drive after a disk change */
static void fd_revalidate (fdrive_t *drv)
{
int64_t nb_sectors;
fd_format_t *parse;
int64_t nb_sectors, size;
int i, first_match, match;
int nb_heads, max_track, last_sect, ro;
FLOPPY_DPRINTF("revalidate\n");
drv->drflags &= ~FDRIVE_REVALIDATE;
/* if no drive present, cannot do more */
if (!drv->bs)
return;
if (bdrv_is_inserted(drv->bs)) {
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
ro = bdrv_is_read_only(drv->bs);
bdrv_get_geometry_hint(drv->bs, &max_track, &nb_heads, &last_sect);
bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
drv->disk = FDRIVE_DISK_USER;
printf("User defined disk (%d %d %d)",
nb_heads - 1, max_track, last_sect);
} else {
bdrv_get_geometry(drv->bs, &nb_sectors);
match = -1;
first_match = -1;
for (i = 0;; i++) {
parse = &fd_formats[i];
if (parse->drive == FDRIVE_DRV_NONE)
break;
if (drv->drive == parse->drive ||
drv->drive == FDRIVE_DRV_NONE) {
size = (parse->max_head + 1) * parse->max_track *
parse->last_sect;
if (nb_sectors == size) {
match = i;
break;
}
if (first_match == -1)
first_match = i;
}
}
if (match == -1) {
if (first_match == -1)
match = 1;
else
match = first_match;
parse = &fd_formats[match];
}
nb_heads = parse->max_head + 1;
max_track = parse->max_track;
last_sect = parse->last_sect;
drv->drive = parse->drive;
printf("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
nb_heads, max_track, last_sect, ro ? "ro" : "rw");
}
if (nb_heads == 1) {
drv->flags &= ~FDISK_DBL_SIDES;
} else {
@ -198,236 +283,9 @@ static void fd_revalidate (fdrive_t *drv)
}
drv->max_track = max_track;
drv->last_sect = last_sect;
} else {
bdrv_get_geometry(drv->bs, &nb_sectors);
switch (nb_sectors) {
/* 2.88 MB 3"1/2 drive disks */
case 7680:
printf("3.84 Mb 3\"1/2 disk (1 80 48)");
drv->drive = FDRIVE_DRV_288;
drv->disk = FDRIVE_DISK_288;
drv->last_sect = 48;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 7040:
printf("3.52 Mb 3\"1/2 disk (1 80 44)");
drv->drive = FDRIVE_DRV_288;
drv->disk = FDRIVE_DISK_288;
drv->last_sect = 44;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 6400:
printf("3.2 Mb 3\"1/2 disk (1 80 40)");
drv->drive = FDRIVE_DRV_288;
drv->disk = FDRIVE_DISK_288;
drv->last_sect = 40;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 6240:
printf("3.12 Mb 3\"1/2 disk (1 80 39)");
drv->drive = FDRIVE_DRV_288;
drv->disk = FDRIVE_DISK_288;
drv->last_sect = 39;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 5760:
printf("2.88 Mb 3\"1/2 disk (1 80 36)");
drv->drive = FDRIVE_DRV_288;
drv->disk = FDRIVE_DISK_288;
drv->last_sect = 36;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
/* 1.44 MB 3"1/2 drive disks */
case 3840:
printf("1.92 Mb 3\"1/2 disk (1 80 24)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 24;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 3680:
printf("1.84 Mb 3\"1/2 disk (1 80 23)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 23;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 3520:
printf("1.76 Mb 3\"1/2 disk (1 80 22)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 22;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 3486:
printf("1.74 Mb 3\"1/2 disk (1 83 21)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 21;
drv->max_track = 83;
drv->flags |= FDISK_DBL_SIDES;
break;
case 3444:
printf("1.72 Mb 3\"1/2 disk (1 82 21)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 21;
drv->max_track = 82;
drv->flags |= FDISK_DBL_SIDES;
break;
case 3360:
printf("1.68 Mb 3\"1/2 disk (1 80 21)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 21;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 3200:
printf("1.6 Mb 3\"1/2 disk (1 80 20)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 20;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 2880:
default:
printf("1.44 Mb 3\"1/2 disk (1 80 18)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_144;
drv->last_sect = 18;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
/* 720 kB 3"1/2 drive disks */
case 2240:
printf("1.12 Mb 3\"1/2 disk (1 80 14)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_720;
drv->last_sect = 14;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 2080:
printf("1.04 Mb 3\"1/2 disk (1 80 13)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_720;
drv->last_sect = 13;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 1660:
printf("830 kb 3\"1/2 disk (1 83 10)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_720;
drv->last_sect = 10;
drv->max_track = 83;
drv->flags |= FDISK_DBL_SIDES;
break;
case 1640:
printf("820 kb 3\"1/2 disk (1 82 10)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_720;
drv->last_sect = 10;
drv->max_track = 82;
drv->flags |= FDISK_DBL_SIDES;
break;
case 1600:
printf("800 kb 3\"1/2 disk (1 80 10)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_720;
drv->last_sect = 10;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 1440:
printf("720 kb 3\"1/2 disk (1 80 9)");
drv->drive = FDRIVE_DRV_144;
drv->disk = FDRIVE_DISK_720;
drv->last_sect = 9;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
/* 1.2 MB 5"1/4 drive disks */
case 2988:
printf("1.49 Mb 5\"1/4 disk (1 83 18)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 18;
drv->max_track = 83;
drv->flags |= FDISK_DBL_SIDES;
break;
case 2952:
printf("1.48 Mb 5\"1/4 disk (1 82 18)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 18;
drv->max_track = 82;
drv->flags |= FDISK_DBL_SIDES;
break;
case 2400:
printf("1.2 Mb 5\"1/4 disk (1 80 15)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 15;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
case 1760:
printf("880 kb 5\"1/4 disk (1 80 11)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 11;
drv->max_track = 80;
drv->flags |= FDISK_DBL_SIDES;
break;
/* 360 kB 5"1/4 drive disks */
case 840:
/* 420 kB 5"1/4 disk */
printf("420 kb 5\"1/4 disk (1 42 10)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 10;
drv->max_track = 42;
drv->flags |= FDISK_DBL_SIDES;
case 820:
/* 410 kB 5"1/4 disk */
printf("410 kb 5\"1/4 disk (1 41 10)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 10;
drv->max_track = 41;
drv->flags |= FDISK_DBL_SIDES;
case 720:
/* 360 kB 5"1/4 disk */
printf("360 kb 5\"1/4 disk (1 40 9)");
drv->drive = FDRIVE_DRV_120;
drv->disk = FDRIVE_DISK_144; /* ? */
drv->last_sect = 9;
drv->max_track = 40;
drv->flags |= FDISK_DBL_SIDES;
break;
}
printf(" %s\n", ro == 0 ? "rw" : "ro");
}
drv->ro = ro;
} else {
printf("No disk in drive\n");
drv->disk = FDRIVE_DISK_NONE;
drv->last_sect = 0;
drv->max_track = 0;
drv->flags &= ~FDISK_DBL_SIDES;
@ -544,20 +402,29 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg)
fdctrl_t *fdctrl = opaque;
uint32_t retval;
if (reg == fdctrl->io_base + 0x01)
switch (reg & 0x07) {
case 0x01:
retval = fdctrl_read_statusB(fdctrl);
else if (reg == fdctrl->io_base + 0x02)
break;
case 0x02:
retval = fdctrl_read_dor(fdctrl);
else if (reg == fdctrl->io_base + 0x03)
break;
case 0x03:
retval = fdctrl_read_tape(fdctrl);
else if (reg == fdctrl->io_base + 0x04)
break;
case 0x04:
retval = fdctrl_read_main_status(fdctrl);
else if (reg == fdctrl->io_base + 0x05)
break;
case 0x05:
retval = fdctrl_read_data(fdctrl);
else if (reg == fdctrl->io_base + 0x07)
break;
case 0x07:
retval = fdctrl_read_dir(fdctrl);
else
break;
default:
retval = (uint32_t)(-1);
break;
}
return retval;
}
@ -566,14 +433,22 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
{
fdctrl_t *fdctrl = opaque;
if (reg == fdctrl->io_base + 0x02)
switch (reg & 0x07) {
case 0x02:
fdctrl_write_dor(fdctrl, value);
else if (reg == fdctrl->io_base + 0x03)
break;
case 0x03:
fdctrl_write_tape(fdctrl, value);
else if (reg == fdctrl->io_base + 0x04)
break;
case 0x04:
fdctrl_write_rate(fdctrl, value);
else if (reg == fdctrl->io_base + 0x05)
break;
case 0x05:
fdctrl_write_data(fdctrl, value);
break;
default:
break;
}
}
static void fd_change_cb (void *opaque)
@ -581,7 +456,6 @@ static void fd_change_cb (void *opaque)
fdrive_t *drv = opaque;
FLOPPY_DPRINTF("disk change\n");
/* TODO: use command-line parameters to force geometry */
fd_revalidate(drv);
#if 0
fd_recalibrate(drv);
@ -606,7 +480,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
fdctrl->irq_lvl = irq_lvl;
fdctrl->dma_chann = dma_chann;
fdctrl->io_base = io_base;
fdctrl->config = 0x40; /* Implicit seek, polling & FIFO enabled */
fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
if (fdctrl->dma_chann != -1) {
fdctrl->dma_en = 1;
DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
@ -634,9 +508,10 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
}
for (i = 0; i < MAX_FD; i++) {
for (i = 0; i < 2; i++) {
fd_revalidate(&fdctrl->drives[i]);
}
return fdctrl;
}

View file

@ -174,7 +174,7 @@ static inline void pic_intack(PicState *s, int irq)
s->irr &= ~(1 << irq);
}
int cpu_x86_get_pic_interrupt(CPUState *env)
int cpu_get_pic_interrupt(CPUState *env)
{
int irq, irq2, intno;

486
hw/m48t59.c Normal file
View file

@ -0,0 +1,486 @@
/*
* QEMU M48T59 NVRAM emulation for PPC PREP platform
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h> /* needed by vl.h */
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "vl.h"
//#define NVRAM_DEBUG
#if defined(NVRAM_DEBUG)
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
#else
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
typedef struct m48t59_t {
/* Hardware parameters */
int IRQ;
uint32_t io_base;
uint16_t size;
/* RTC management */
time_t time_offset;
time_t stop_time;
/* Alarm & watchdog */
time_t alarm;
struct QEMUTimer *alrm_timer;
struct QEMUTimer *wd_timer;
/* NVRAM storage */
uint16_t addr;
uint8_t *buffer;
} m48t59_t;
static m48t59_t *NVRAMs;
static int nb_NVRAMs;
/* Fake timer functions */
/* Generic helpers for BCD */
static inline uint8_t toBCD (uint8_t value)
{
return (((value / 10) % 10) << 4) | (value % 10);
}
static inline uint8_t fromBCD (uint8_t BCD)
{
return ((BCD >> 4) * 10) + (BCD & 0x0F);
}
/* RTC management helpers */
static void get_time (m48t59_t *NVRAM, struct tm *tm)
{
time_t t;
t = time(NULL) + NVRAM->time_offset;
localtime_r(&t, tm);
}
static void set_time (m48t59_t *NVRAM, struct tm *tm)
{
time_t now, new_time;
new_time = mktime(tm);
now = time(NULL);
NVRAM->time_offset = new_time - now;
}
/* Alarm management */
static void alarm_cb (void *opaque)
{
struct tm tm, tm_now;
uint64_t next_time;
m48t59_t *NVRAM = opaque;
pic_set_irq(NVRAM->IRQ, 1);
if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a month */
get_time(NVRAM, &tm_now);
memcpy(&tm, &tm_now, sizeof(struct tm));
tm.tm_mon++;
if (tm.tm_mon == 13) {
tm.tm_mon = 1;
tm.tm_year++;
}
next_time = mktime(&tm);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a day */
next_time = 24 * 60 * 60 + mktime(&tm_now);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once an hour */
next_time = 60 * 60 + mktime(&tm_now);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a minute */
next_time = 60 + mktime(&tm_now);
} else {
/* Repeat once a second */
next_time = 1 + mktime(&tm_now);
}
qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
pic_set_irq(NVRAM->IRQ, 0);
}
static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
{
localtime_r(&NVRAM->alarm, tm);
}
static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
{
NVRAM->alarm = mktime(tm);
if (NVRAM->alrm_timer != NULL) {
qemu_del_timer(NVRAM->alrm_timer);
NVRAM->alrm_timer = NULL;
}
if (NVRAM->alarm - time(NULL) > 0)
qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
}
/* Watchdog management */
static void watchdog_cb (void *opaque)
{
m48t59_t *NVRAM = opaque;
NVRAM->buffer[0x1FF0] |= 0x80;
if (NVRAM->buffer[0x1FF7] & 0x80) {
NVRAM->buffer[0x1FF7] = 0x00;
NVRAM->buffer[0x1FFC] &= ~0x40;
// reset_CPU();
} else {
pic_set_irq(NVRAM->IRQ, 1);
pic_set_irq(NVRAM->IRQ, 0);
}
}
static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
{
uint64_t interval; /* in 1/16 seconds */
if (NVRAM->wd_timer != NULL) {
qemu_del_timer(NVRAM->wd_timer);
NVRAM->wd_timer = NULL;
}
NVRAM->buffer[0x1FF0] &= ~0x80;
if (value != 0) {
interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
((interval * 1000) >> 4));
}
}
/* Direct access to NVRAM */
void m48t59_write (void *opaque, uint32_t val)
{
m48t59_t *NVRAM = opaque;
struct tm tm;
int tmp;
if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register : read-only */
break;
case 0x1FF1:
/* unused */
break;
case 0x1FF2:
/* alarm seconds */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_sec = tmp;
NVRAM->buffer[0x1FF2] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF3:
/* alarm minutes */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_min = tmp;
NVRAM->buffer[0x1FF3] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF4:
/* alarm hours */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_alarm(NVRAM, &tm);
tm.tm_hour = tmp;
NVRAM->buffer[0x1FF4] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF5:
/* alarm date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_alarm(NVRAM, &tm);
tm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF6:
/* interrupts */
NVRAM->buffer[0x1FF6] = val;
break;
case 0x1FF7:
/* watchdog */
NVRAM->buffer[0x1FF7] = val;
set_up_watchdog(NVRAM, val);
break;
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
break;
case 0x1FF9:
/* seconds (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_sec = tmp;
set_time(NVRAM, &tm);
}
if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
if (val & 0x80) {
NVRAM->stop_time = time(NULL);
} else {
NVRAM->time_offset += NVRAM->stop_time - time(NULL);
NVRAM->stop_time = 0;
}
}
NVRAM->buffer[0x1FF9] = val & 0x80;
break;
case 0x1FFA:
/* minutes (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_min = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFB:
/* hours (BCD) */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_time(NVRAM, &tm);
tm.tm_hour = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFC:
/* day of the week / century */
tmp = fromBCD(val & 0x07);
get_time(NVRAM, &tm);
tm.tm_wday = tmp;
set_time(NVRAM, &tm);
NVRAM->buffer[0x1FFC] = val & 0x40;
break;
case 0x1FFD:
/* date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFE:
/* month */
tmp = fromBCD(val & 0x1F);
if (tmp >= 1 && tmp <= 12) {
get_time(NVRAM, &tm);
tm.tm_mon = tmp - 1;
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
NVRAM->buffer[NVRAM->addr] = val & 0xFF;
}
break;
}
}
uint32_t m48t59_read (void *opaque)
{
m48t59_t *NVRAM = opaque;
struct tm tm;
uint32_t retval = 0xFF;
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register */
goto do_read;
case 0x1FF1:
/* unused */
retval = 0;
break;
case 0x1FF2:
/* alarm seconds */
goto do_read;
case 0x1FF3:
/* alarm minutes */
goto do_read;
case 0x1FF4:
/* alarm hours */
goto do_read;
case 0x1FF5:
/* alarm date */
goto do_read;
case 0x1FF6:
/* interrupts */
goto do_read;
case 0x1FF7:
/* A read resets the watchdog */
set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
goto do_read;
case 0x1FF8:
/* control */
goto do_read;
case 0x1FF9:
/* seconds (BCD) */
get_time(NVRAM, &tm);
retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
break;
case 0x1FFA:
/* minutes (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_min);
break;
case 0x1FFB:
/* hours (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_hour);
break;
case 0x1FFC:
/* day of the week / century */
get_time(NVRAM, &tm);
retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
break;
case 0x1FFD:
/* date */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mday);
break;
case 0x1FFE:
/* month */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mon + 1);
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
break;
default:
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
do_read:
retval = NVRAM->buffer[NVRAM->addr];
}
break;
}
if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
return retval;
}
void m48t59_set_addr (void *opaque, uint32_t addr)
{
m48t59_t *NVRAM = opaque;
NVRAM->addr = addr;
}
/* IO access to NVRAM */
static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->io_base;
switch (addr) {
case 0:
NVRAM->addr &= ~0x00FF;
NVRAM->addr |= val;
break;
case 1:
NVRAM->addr &= ~0xFF00;
NVRAM->addr |= val << 8;
break;
case 3:
m48t59_write(NVRAM, val);
NVRAM->addr = 0x0000;
break;
default:
break;
}
}
static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
{
m48t59_t *NVRAM = opaque;
if (addr == NVRAM->io_base + 3)
return m48t59_read(NVRAM);
return 0xFF;
}
/* Initialisation routine */
void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size)
{
m48t59_t *tmp;
tmp = realloc(NVRAMs, (nb_NVRAMs + 1) * sizeof(m48t59_t));
if (tmp == NULL)
return NULL;
NVRAMs = tmp;
tmp[nb_NVRAMs].buffer = malloc(size);
if (tmp[nb_NVRAMs].buffer == NULL)
return NULL;
memset(tmp[nb_NVRAMs].buffer, 0, size);
tmp[nb_NVRAMs].IRQ = IRQ;
tmp[nb_NVRAMs].size = size;
tmp[nb_NVRAMs].io_base = io_base;
tmp[nb_NVRAMs].addr = 0;
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, &NVRAMs[nb_NVRAMs]);
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, &NVRAMs[nb_NVRAMs]);
tmp[nb_NVRAMs].alrm_timer = qemu_new_timer(vm_clock, &alarm_cb,
&tmp[nb_NVRAMs]);
tmp[nb_NVRAMs].wd_timer = qemu_new_timer(vm_clock, &watchdog_cb,
&tmp[nb_NVRAMs]);
return &NVRAMs[nb_NVRAMs++];
}

9
hw/m48t59.h Normal file
View file

@ -0,0 +1,9 @@
#if !defined (__M48T59_H__)
#define __M48T59_H__
void m48t59_write (void *opaque, uint32_t val);
uint32_t m48t59_read (void *opaque);
void m48t59_set_addr (void *opaque, uint32_t addr);
void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size);
#endif /* !defined (__M48T59_H__) */

View file

@ -146,6 +146,10 @@ static void ne2000_update_irq(NE2000State *s)
{
int isr;
isr = s->isr & s->imr;
#if defined(DEBUG_NE2000)
printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
s->irq, isr ? 1 : 0, s->isr, s->imr);
#endif
if (isr)
pic_set_irq(s->irq, 1);
else

42
hw/ppc.c Normal file
View file

@ -0,0 +1,42 @@
/*
* QEMU generic PPC hardware System Emulator
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "vl.h"
void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename);
void ppc_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
/* For now, only PREP is supported */
return ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
}

1007
hw/ppc_prep.c Normal file

File diff suppressed because it is too large Load diff